icecat: add release icecat-140.8.0-2 for aramo

This commit is contained in:
Ark74 2026-03-11 06:58:43 -06:00
parent d9a6c0aa96
commit d570f39e11
616 changed files with 39955 additions and 33937 deletions

View file

@ -100,9 +100,9 @@ git = "https://github.com/mozilla/midir.git"
rev = "85156e360a37d851734118104619f86bd18e94c6"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/mp4parse-rust?rev=e64650a686e5c5732395cd059e17cfd3b1e5b63b"]
[source."git+https://github.com/mozilla/mp4parse-rust?rev=25ebfa59a21dc0d223052d73a2fafdd55307c2d7"]
git = "https://github.com/mozilla/mp4parse-rust"
rev = "e64650a686e5c5732395cd059e17cfd3b1e5b63b"
rev = "25ebfa59a21dc0d223052d73a2fafdd55307c2d7"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/neqo?tag=v0.13.4"]

4
icecat/.gitignore vendored
View file

@ -37,6 +37,10 @@ ID
# third-party packages is dealt with by the script vendoring them.
*.egg-info/
# Ignore pywebsocket3 intermediate files.
testing/web-platform/tests/tools/third_party/pywebsocket3/pywebsocket3.egg-info
testing/web-platform/tests/tools/third_party/pywebsocket3/build
# Vim swap files.
.*.sw[a-z]
.sw[a-z]

View file

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Merge day clobber 2025-12-08
Merge day clobber 2026-01-12

4
icecat/Cargo.lock generated
View file

@ -4607,7 +4607,7 @@ dependencies = [
[[package]]
name = "mp4parse"
version = "0.17.0"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=e64650a686e5c5732395cd059e17cfd3b1e5b63b#e64650a686e5c5732395cd059e17cfd3b1e5b63b"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=25ebfa59a21dc0d223052d73a2fafdd55307c2d7#25ebfa59a21dc0d223052d73a2fafdd55307c2d7"
dependencies = [
"bitreader",
"byteorder",
@ -4624,7 +4624,7 @@ version = "0.1.0"
[[package]]
name = "mp4parse_capi"
version = "0.17.0"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=e64650a686e5c5732395cd059e17cfd3b1e5b63b#e64650a686e5c5732395cd059e17cfd3b1e5b63b"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=25ebfa59a21dc0d223052d73a2fafdd55307c2d7#25ebfa59a21dc0d223052d73a2fafdd55307c2d7"
dependencies = [
"byteorder",
"fallible_collections",

View file

@ -11,7 +11,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/DynamicallyLinkedFunctionPtr.h"
#include "mozilla/glue/Debug.h"
#include "mozilla/GeckoArgs.h"
#include "mozilla/Maybe.h"
@ -19,12 +18,14 @@
#include "mozilla/SafeMode.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WindowsConsole.h"
#include "mozilla/WindowsProcessMitigations.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/WinHeaderOnlyUtils.h"
#include "nsWindowsHelpers.h"
#include <windows.h>
#include <processthreadsapi.h>
#include <shlwapi.h>
#include "DllBlocklistInit.h"
#include "ErrorHandler.h"
@ -111,16 +112,82 @@ static nsReturnRef<HANDLE> CreateJobAndAssignProcess(HANDLE aProcess) {
return job.out();
}
#if !defined( \
PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON)
# define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON \
(0x00000001ULL << 60)
#endif // !defined(PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON)
enum class VCRuntimeDLLDir : bool {
Application,
System,
};
static bool GetMSVCP140VersionInfo(VCRuntimeDLLDir aDir,
uint64_t& aOutVersion) {
wchar_t dllPath[MAX_PATH];
if (aDir == VCRuntimeDLLDir::Application) {
DWORD size = ::GetModuleFileNameW(nullptr, dllPath, MAX_PATH);
if (!size ||
(size == MAX_PATH && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) ||
!::PathRemoveFileSpecW(dllPath)) {
return false;
}
} else {
MOZ_ASSERT(aDir == VCRuntimeDLLDir::System);
UINT size = ::GetSystemDirectoryW(dllPath, MAX_PATH);
if (!size || size >= MAX_PATH) {
return false;
}
}
#if !defined(PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF)
# define PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF \
(0x00000002ULL << 40)
#endif // !defined(PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF)
if (!::PathAppendW(dllPath, L"msvcp140.dll")) {
return false;
}
HMODULE crt =
::LoadLibraryExW(dllPath, nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if (!crt) {
return false;
}
mozilla::nt::PEHeaders headers{crt};
bool result = headers.GetVersionInfo(aOutVersion);
::FreeLibrary(crt);
return result;
}
/**
* Choose whether we want to favor loading DLLs from the system directory over
* the application directory. This choice automatically propagates to all child
* processes. In particular, it determines whether child processes will load
* Visual C++ runtime DLLs from the system or the application directory at
* startup.
*
* Whenever possible, we want all processes to favor loading DLLs from the
* system directory. But if old Visual C++ runtime DLLs are installed
* system-wide, then we must favor loading from the application directory
* instead to ensure compatibility, at least during startup. So in this case we
* only apply the delayed variant of the mitigation and only in sandboxed
* processes, which is the best compromise (see SandboxBroker::LaunchApp).
*
* This function is called from the launcher process *and* the browser process.
* This is because if the launcher process is disabled, we still want the
* browser process to go through this code so that it enforces the correct
* choice for itself and for child processes.
*/
static void EnablePreferLoadFromSystem32IfCompatible() {
// We may already have the mitigation if we are the browser process and we
// inherited it from the launcher process.
if (!mozilla::IsPreferLoadFromSystem32Available() ||
mozilla::IsPreferLoadFromSystem32Enabled()) {
return;
}
// Only bail out if (1) there is a conflict because the two DLLs exist *and*
// (2) the version of the system DLL is problematic.
uint64_t systemDirVersion = 0, appDirVersion = 0;
if (GetMSVCP140VersionInfo(VCRuntimeDLLDir::System, systemDirVersion) &&
GetMSVCP140VersionInfo(VCRuntimeDLLDir::Application, appDirVersion) &&
systemDirVersion < appDirVersion) {
return;
}
mozilla::DebugOnly<bool> setOk = mozilla::EnablePreferLoadFromSystem32();
MOZ_ASSERT(setOk);
}
/**
* Any mitigation policies that should be set on the browser process should go
@ -128,10 +195,11 @@ static nsReturnRef<HANDLE> CreateJobAndAssignProcess(HANDLE aProcess) {
*/
static void SetMitigationPolicies(mozilla::ProcThreadAttributes& aAttrs,
const bool aIsSafeMode) {
if (mozilla::IsWin10AnniversaryUpdateOrLater()) {
aAttrs.AddMitigationPolicy(
PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON);
}
// Note: Do *not* handle IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON here. For this
// mitigation we rely on EnablePreferLoadFromSystem32IfCompatible().
// The launcher process or the browser process will choose whether we
// want to apply the mitigation or not, and child processes will
// automatically inherit that choice.
#if defined(_M_ARM64)
// Disable CFG on older versions of ARM64 Windows to avoid a crash in COM.
@ -286,6 +354,9 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
return Nothing();
}
// Called from the launcher process *and* the browser process.
EnablePreferLoadFromSystem32IfCompatible();
#if defined(MOZ_LAUNCHER_PROCESS)
LauncherRegistryInfo regInfo;
Maybe<bool> runAsLauncher = RunAsLauncherProcess(regInfo, argc, argv);
@ -309,22 +380,6 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
return Nothing();
}
// Make sure that the launcher process itself has image load policies set
if (IsWin10AnniversaryUpdateOrLater()) {
static const StaticDynamicallyLinkedFunctionPtr<
decltype(&SetProcessMitigationPolicy)>
pSetProcessMitigationPolicy(L"kernel32.dll",
"SetProcessMitigationPolicy");
if (pSetProcessMitigationPolicy) {
PROCESS_MITIGATION_IMAGE_LOAD_POLICY imgLoadPol = {};
imgLoadPol.PreferSystem32Images = 1;
DebugOnly<BOOL> setOk = pSetProcessMitigationPolicy(
ProcessImageLoadPolicy, &imgLoadPol, sizeof(imgLoadPol));
MOZ_ASSERT(setOk);
}
}
#if defined(MOZ_SANDBOX)
// Ensure the relevant mitigations are enforced.
mozilla::sandboxing::ApplyParentProcessMitigations();

View file

@ -24,6 +24,7 @@ OS_LIBS += [
"oleaut32",
"ole32",
"rpcrt4",
"shlwapi",
"version",
]

View file

@ -127,6 +127,9 @@ let JSWINDOWACTORS = {
},
},
matches: ["about:messagepreview", "about:messagepreview?*"],
remoteTypes: ["privilegedabout"],
enablePreference:
"browser.newtabpage.activity-stream.asrouter.devtoolsEnabled",
},
AboutPocket: {

View file

@ -110,6 +110,7 @@ static const RedirEntry kRedirMap[] = {
{"messagepreview",
"chrome://browser/content/messagepreview/messagepreview.html",
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT},
{"pocket-saved", "chrome://pocket/content/panels/saved.html",

View file

@ -14,8 +14,8 @@ add_task(async function test_recover_storeID() {
await SelectableProfileService.init();
Assert.ok(
!ProfilesDatastoreService.initialized,
"Didn't initialize the datastore service"
ProfilesDatastoreService.initialized,
"Initialized the datastore service"
);
Assert.ok(
!SelectableProfileService.initialized,

View file

@ -15,6 +15,7 @@
#include "mozilla/Result.h"
#include "mozilla/ResultVariant.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/WinHeaderOnlyUtils.h"
#include "mozilla/widget/WinTaskbar.h"
#include "WinUtils.h"
@ -186,7 +187,16 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
Win11PinToTaskBarResult unlockStatus =
UnlockLimitedAccessFeature(Win11LimitedAccessFeatureType::Taskbar);
if (unlockStatus.result != Win11PinToTaskBarResultStatus::Success) {
return unlockStatus;
// Limited Access Feature no longer necessary for Windows 11 26200 Build
// 7840, and possibly other channels.
if (!IsWin11OrLater()) {
return unlockStatus;
}
TASKBAR_PINNING_LOG(
LogLevel::Warning,
"Limited Access Feature failed to unlock, attempting to use Taskbar "
"Pinning API assuming LAF is no longer necessary.");
}
HRESULT hr;
@ -407,7 +417,16 @@ Win11PinToTaskBarResult IsCurrentAppPinnedToTaskbarWin11(bool aCheckOnly) {
Win11PinToTaskBarResult unlockStatus =
UnlockLimitedAccessFeature(Win11LimitedAccessFeatureType::Taskbar);
if (unlockStatus.result != Win11PinToTaskBarResultStatus::Success) {
return unlockStatus;
// Limited Access Feature no longer necessary for Windows 11 26200 Build
// 7840, and possibly other channels.
if (!IsWin11OrLater()) {
return unlockStatus;
}
TASKBAR_PINNING_LOG(
LogLevel::Warning,
"Limited Access Feature failed to unlock, attempting to use Taskbar "
"Pinning API assuming LAF is no longer necessary.");
}
HRESULT hr;

View file

@ -1 +1 @@
140.7.1
140.8.0

View file

@ -1 +1 @@
140.7.1esr
140.8.0esr

View file

@ -13,5 +13,5 @@ MOZ_BRANDING_DIRECTORY=browser/branding/unofficial
MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official
# IceCat settings
MOZ_APP_BASENAME=IceCat
MOZ_APP_VERSION=140.7.1
MOZ_APP_VERSION=140.8.0
MOZ_DATA_REPORTING=0

View file

@ -1473,6 +1473,9 @@ async function triggerCapture(browser, submitButtonSelector, fillSelectors) {
* @param {object} patterns.captureExpectedRecord
* The expected saved record after capturing the form. Keyed by field name. This
* parameter is only used when `options.testCapture` is set.
* @param {boolean} patterns.useTestYear
* Set to the current year to assign while running the test, useful for credit
* card expiry tests with a manual set of year options in the dropdown.
* @param {object} patterns.only
* This parameter is used solely for debugging purposes. When set to true,
* it restricts the execution to only the specified testcase.
@ -1597,16 +1600,32 @@ async function add_heuristic_tests(
const sleepAfterFocus = contexts.length > 1;
for (const context of contexts) {
await SpecialPowers.spawn(context, [], async () => {
const elements = Array.from(
content.document.querySelectorAll("input, select")
);
// Focus on each field in the test document to trigger autofill field detection
// on all the fields.
elements.forEach(element => {
element.focus();
});
});
await SpecialPowers.spawn(
context,
[testPattern.useTestYear],
async year => {
let FormAutofillHeuristics;
if (year) {
FormAutofillHeuristics = ChromeUtils.importESModule(
"resource://gre/modules/shared/FormAutofillHeuristics.sys.mjs"
).FormAutofillHeuristics;
FormAutofillHeuristics.useTestYear = year;
}
const elements = Array.from(
content.document.querySelectorAll("input, select")
);
// Focus on each field in the test document to trigger autofill field detection
// on all the fields.
elements.forEach(element => {
element.focus();
});
if (year) {
FormAutofillHeuristics.useTestYear = null;
}
}
);
try {
await BrowserTestUtils.synthesizeKey("VK_ESCAPE", {}, context);

View file

@ -8,7 +8,6 @@ support-files = [
["browser_BestBuy.js"]
["browser_CDW.js"]
skip-if = ["true"] # Bug 1939626
["browser_CostCo.js"]

View file

@ -30,6 +30,7 @@ add_heuristic_tests(
},
{
fixturePath: "Checkout_BillingPaymentInfo.html",
useTestYear: 2024,
expectedResult: [
{
default: {

View file

@ -74,6 +74,7 @@ add_heuristic_tests(
},
{
fixturePath: "Payment.html",
useTestYear: 2025,
expectedResult: [
{
default: {

View file

@ -6,6 +6,7 @@ add_heuristic_tests(
[
{
fixturePath: "Payment.html",
useTestYear: 2024,
expectedResult: [
{
default: {

View file

@ -6,6 +6,7 @@ add_heuristic_tests(
[
{
fixturePath: "Checkout_Payment.html",
useTestYear: 2024,
expectedResult: [
{
default: {

View file

@ -6,6 +6,7 @@ add_heuristic_tests(
[
{
fixturePath: "index.html",
useTestYear: 2024,
expectedResult: [
{
default: {

View file

@ -120,3 +120,65 @@ window.wrappedJSObject.chrome = cloneInto(
window,
{ cloneFunctions: true }
);
const ua = navigator.userAgent;
const mobile = ua.includes("Mobile") || ua.includes("Tablet");
// Very roughly matches Chromium's GetPlatformForUAMetadata()
let platform = "Linux";
if (mobile) {
platform = "Android";
} else if (navigator.platform.startsWith("Win")) {
platform = "Windows";
} else if (navigator.platform.startsWith("Mac")) {
platform = "macOS";
}
const version = (ua.match(/IceCat\/([0-9]+)/) || ["", "58.0"])[1];
// These match Chrome's output as of version 126.
const brands = [
{
brand: "Not/A)Brand",
version: "8",
},
{
brand: "Chromium",
version,
},
{
brand: "Google Chrome",
version,
},
];
const userAgentData = cloneInto(
{
brands,
mobile,
platform,
getHighEntropyValues() {
return window.wrappedJSObject.Promise.resolve(
cloneInto(
{
brands,
mobile,
platform,
platformVersion: "19.0.0",
},
window
)
);
},
},
window,
{ cloneFunctions: true }
);
Object.defineProperty(window.navigator.wrappedJSObject, "userAgentData", {
get: exportFunction(function () {
return userAgentData;
}, window),
set: exportFunction(function () {}, window),
});

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Web Compatibility Interventions",
"description": "Urgent post-release fixes for web compatibility.",
"version": "140.11.0",
"version": "140.12.0",
"browser_specific_settings": {
"gecko": {
"id": "webcompat@mozilla.org",

Binary file not shown.

Binary file not shown.

View file

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
140.7.1
140.8.0

View file

@ -157,8 +157,12 @@ ifeq (official, $(MOZ_BRANDING))
MOZ_DEFINES += -DMOZ_OFFICIAL_BRANDING
endif
ifneq (,$(DEB_PARALLEL_JOBS))
ifneq (,$(filter armhf, $(DEB_HOST_ARCH)))
MOZ_DEFINES += -DDEB_PARALLEL_JOBS=1
else
MOZ_DEFINES += -DDEB_PARALLEL_JOBS=$(DEB_PARALLEL_JOBS)
endif
endif
MOZ_EXECUTABLES_$(MOZ_PKG_NAME) += $(MOZ_LIBDIR)/$(MOZ_PKG_BASENAME).sh \
$(NULL)

View file

@ -1,3 +1,9 @@
icecat (140.8.0-2gnu1+build1-0.11.0) aramo; urgency=medium
* New upstream stable release (icecat-140.8.0-2gnu1)
-- Capitulo Mexicano de Software Libre <devel@cmxsl.org> Tue, 10 Mar 2026 22:35:37 -0600
icecat (140.7.1-1gnu1+build1-0.11.0) aramo; urgency=medium
* New upstream stable release (icecat-140.7.1-1gnu1)

View file

@ -11,7 +11,11 @@ ac_add_options --disable-updater
ac_add_options --enable-application=browser
ac_add_options --with-distribution-id=org.trisquel
%%if DEB_BUILD_ARCH_BITS == 32
%%if DEB_HOST_ARCH == armhf
ac_add_options --disable-debug-symbols
%%else
ac_add_options --enable-debug-symbols=-g1
%%endif
%%else
ac_add_options --enable-debug-symbols
%%endif

View file

@ -1,22 +1,30 @@
Description: Do not enable LTO for rustc when building on arm64 and armhf,
Description: Do not enable LTO for rustc when building on armhf,
to work around OOM failures on Launchpad builders. Note that this alone is not
sufficient, because by default cargo will also enable full LTO when building
with a release profile, so the top-level Cargo.toml file needs to be
conditionally patched (this is done in debian/build/rules.mk).
Author: Olivier Tilloy <olivier.tilloy@canonical.com>
Author: Nathan Pratte Teodosio <nteodosio@ubuntu.com>
Forwarded: not-needed
--- a/config/makefiles/rust.mk
+++ b/config/makefiles/rust.mk
@@ -70,8 +70,10 @@ ifndef MOZ_DEBUG_RUST
@@ -70,10 +70,18 @@ ifndef MOZ_DEBUG_RUST
# Never enable when coverage is enabled to work around https://github.com/rust-lang/rust/issues/90045.
ifndef MOZ_CODE_COVERAGE
ifeq (,$(findstring gkrust_gtest,$(RUST_LIBRARY_FILE)))
+ifeq (,$(filter aarch64 arm,$(TARGET_CPU)))
+ifneq (,$(filter arm,$(TARGET_CPU)))
+cargo_rustc_flags += -Clto=off
+else
cargo_rustc_flags += -Clto$(if $(filter full,$(MOZ_LTO_RUST_CROSS)),=fat)
endif
+endif
# We need -Cembed-bitcode=yes for all crates when using -Clto.
RUSTFLAGS += -Cembed-bitcode=yes
endif
# We need -Cembed-bitcode=yes for all crates when using -Clto.
+ifneq (,$(filter arm,$(TARGET_CPU)))
+RUSTFLAGS += -Cembed-bitcode=no
+else
RUSTFLAGS += -Cembed-bitcode=yes
+endif
endif
endif
endif

View file

@ -7,7 +7,7 @@ webrtc-fix-compiler-flags-for-armhf.patch
s390x-ycbcr.patch
reduce-rust-debuginfo.patch
armhf-reduce-linker-memory-use.patch
armhf-rustc-thin-lto.patch
armhf-rustc-lto-off.patch
ppc64el-workaround-bug-1555531.patch
ppc64el-workaround-gcc-ice.patch
armhf-clang-no-integrated-as-for-neon.patch

View file

@ -124,30 +124,34 @@ class RequestPanel extends Component {
}
/**
* Mapping array to dict for TreeView usage.
* Since TreeView only support Object(dict) format.
* This function also deal with duplicate key case
* (for multiple selection and query params with same keys)
* This maps an array to a dictionary for TreeView usage,
* sincs the treeView only supports the Object(dict) format.
*
* This function is not sorting result properties since it can
* results in unexpected order of params. See bug 1469533
* This function also deals with the duplicate key scenario
* (i.e multiple selections and query params with same keys)
*
* @param {Object[]} arr - key-value pair array or form params
* @returns {Object} Rep compatible object
* Note: This is not sorting the result properties since it can
* result in an unexpected order of parameters. See bug 1469533
*
* @param {object[]} arrOfKeyValuePairs - An array of key-value pairs or form params.
* @param {string} arrOfKeyValuePairs[].name
* @param {string|Array} arrOfKeyValuePairs[].value
*
* @returns {object} Rep compatible object
*/
getProperties(arr) {
return arr.reduce((map, obj) => {
const value = map[obj.name];
if (value || value === "") {
if (typeof value !== "object") {
map[obj.name] = [value];
getProperties(arrOfKeyValuePairs) {
return arrOfKeyValuePairs.reduce((dict, { name, value }) => {
if (name in dict) {
const dictValue = dict[name];
if (!Array.isArray(dictValue)) {
dict[name] = [dictValue];
}
map[obj.name].push(obj.value);
dict[name].push(value);
} else {
map[obj.name] = obj.value;
dict[name] = value;
}
return map;
}, {});
return dict;
}, Object.create(null));
}
toggleRawRequestPayload() {
@ -205,10 +209,9 @@ class RequestPanel extends Component {
// Form Data section
if (formDataSections && formDataSections.length) {
const sections = formDataSections.filter(str => /\S/.test(str)).join("&");
component = PropertiesView;
componentProps = {
object: this.getProperties(parseFormData(sections)),
object: this.getProperties(parseFormData(formDataSections)),
filterText,
targetSearchResult,
defaultSelectFirstNode: false,

View file

@ -83,7 +83,6 @@ async function getFormDataSections(
}
}
}
return formDataSections;
}
@ -418,28 +417,29 @@ function parseQueryString(query) {
/**
* Parse a string of formdata sections into its components
*
* @param {string} sections - sections of formdata joined by &
* @return {array} array of formdata params { name, value }
* @param {Array<string>} sections Array of sections of formdata
* e.g ["", "a=x&b=y", "c=z"]
* @return {Array<object>} Array of formdata params
* e.g [{ name: 'a', value: 'x' }, { name: 'b', value: 'y'}, { name: 'c', value: 'z'}]
*/
function parseFormData(sections) {
if (!sections) {
if (!sections || !sections.length) {
return [];
}
const formDataParams = [];
const searchStr = sections
// Filter out empty sections
.filter(str => /\S/.test(str))
.join("&");
return sections
.replace(/^&/, "")
.split("&")
.map(e => {
const firstEqualSignIndex = e.indexOf("=");
const paramName =
firstEqualSignIndex !== -1 ? e.slice(0, firstEqualSignIndex) : e;
const paramValue =
firstEqualSignIndex !== -1 ? e.slice(firstEqualSignIndex + 1) : "";
return {
name: paramName ? getUnicodeUrlPath(paramName) : "",
value: paramValue ? getUnicodeUrlPath(paramValue) : "",
};
const params = new URLSearchParams(searchStr);
for (const [key, value] of params) {
formDataParams.push({
name: getUnicodeUrlPath(key),
value: getUnicodeUrlPath(value),
});
}
return formDataParams;
}
/**

View file

@ -20,7 +20,7 @@ add_task(async function () {
store.dispatch(Actions.batchEnable(false));
// Execute requests.
await performRequests(monitor, tab, 12);
await performRequests(monitor, tab, 13);
const requestListItems = document.querySelectorAll(
".network-monitor .request-list-item"
@ -49,7 +49,7 @@ add_task(async function () {
await testRequestWithFormattedView(
monitor,
requestListItems[2],
"?foo",
"foo",
"bar=123=xyz",
"?foo=bar=123=xyz",
1
@ -92,6 +92,14 @@ add_task(async function () {
'{ "foo": "bar" }',
1
);
await testRequestWithFormattedView(
monitor,
requestListItems[12],
"__proto__",
"evil_value",
"__proto__=evil_value",
1
);
await teardown(monitor);
});

View file

@ -326,10 +326,10 @@ function testEscapeStringWin() {
"Percent signs should be escaped."
);
const backslashes = "\\A simple string\\";
const backslashes = " - \\A simple string\\ - ";
is(
CurlUtils.escapeStringWin(backslashes),
'^\"^\\A simple string^\\^\"',
'^\" - ^\\^\\A simple string^\\^\\ - ^\"',
"Backslashes should be escaped."
);

View file

@ -71,6 +71,7 @@
await get("baz", "?species=in=(52,60)");
await get("baz", "?a=&a=b");
await get("baz", "?a=b&a=c&d=1");
await post("baz", "", urlencoded, "__proto__=evil_value");
}
</script>
</body>

View file

@ -458,6 +458,9 @@ const CurlUtils = {
return (
encapsChars +
str
// Replace all the \ (used as the escape character in the next replace) with \\
.replace(/\\/g, "\\\\")
// Replace all " with \" to ensure the first parser does not remove it.
.replace(/"/g, '\\"')

View file

@ -4049,6 +4049,10 @@ bool IPDLParamTraits<dom::MaybeDiscarded<dom::BrowsingContext>>::Read(
if (id == 0) {
*aResult = nullptr;
} else if (RefPtr<dom::BrowsingContext> bc = dom::BrowsingContext::Get(id)) {
if (!bc->Group()->IsKnownForMessageReader(aReader)) {
return false;
}
*aResult = std::move(bc);
} else {
aResult->SetDiscarded(id);

View file

@ -251,6 +251,42 @@ ContentParent* BrowsingContextGroup::GetHostProcess(
return mHosts.GetWeak(aRemoteType);
}
bool BrowsingContextGroup::IsKnownForMessageReader(
IPC::MessageReader* aReader) {
if (!aReader->GetActor()) {
aReader->FatalError(
"No actor for BrowsingContextGroup::IsKnownForMessageReader");
return false;
}
mozilla::ipc::IToplevelProtocol* topActor =
aReader->GetActor()->ToplevelProtocol();
switch (topActor->GetProtocolId()) {
case PInProcessMsgStart:
// PInProcess always exists only within a single process, so we don't need
// to do any validation on it.
return true;
case PContentMsgStart:
// The process should only be able to name this BCG if it is
// subscribed, or if the BCG has been destroyed (and has therefore
// stopped tracking subscribers).
if (topActor->GetSide() == mozilla::ipc::ParentSide && !mDestroyed &&
!mSubscribers.Contains(static_cast<ContentParent*>(topActor))) {
aReader->FatalError(
"Process is not subscribed to this BrowsingContextGroup");
return false;
}
return true;
default:
aReader->FatalError(
"Unsupported toplevel actor for "
"BrowsingContextGroup::IsKnownForMessageReader");
return false;
}
}
void BrowsingContextGroup::UpdateToplevelsSuspendedIfNeeded() {
if (!StaticPrefs::dom_suspend_inactive_enabled()) {
return;
@ -296,8 +332,8 @@ void BrowsingContextGroup::Destroy() {
!sBrowsingContextGroups->Contains(Id()) ||
*sBrowsingContextGroups->Lookup(Id()) != this);
}
mDestroyed = true;
#endif
mDestroyed = true;
// Make sure to call `RemoveBrowsingContextGroup` for every entry in both
// `mHosts` and `mSubscribers`. This will visit most entries twice, but

View file

@ -87,6 +87,12 @@ class BrowsingContextGroup final : public nsWrapperCache {
// BrowsingContextGroup, if possible.
ContentParent* GetHostProcess(const nsACString& aRemoteType);
// Check if the process which sent the message being read from aReader is
// aware of this BrowsingContextGroup's existence.
// If this returns false, it will first set a fatal error on aReader with more
// details.
bool IsKnownForMessageReader(IPC::MessageReader* aReader);
// When a BrowsingContext is being discarded, we may want to keep the
// corresponding BrowsingContextGroup alive until the other process
// acknowledges that the BrowsingContext has been discarded. A `KeepAlive`
@ -260,9 +266,7 @@ class BrowsingContextGroup final : public nsWrapperCache {
uint32_t mKeepAliveCount = 0;
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
bool mDestroyed = false;
#endif
// A BrowsingContextGroup contains a series of {Browsing,Window}Context
// objects. They are addressed using a hashtable to avoid linear lookup when

View file

@ -764,6 +764,10 @@ bool IPDLParamTraits<dom::MaybeDiscarded<dom::WindowContext>>::Read(
if (id == 0) {
*aResult = nullptr;
} else if (RefPtr<dom::WindowContext> wc = dom::WindowContext::GetById(id)) {
if (!wc->Group()->IsKnownForMessageReader(aReader)) {
return false;
}
*aResult = std::move(wc);
} else {
aResult->SetDiscarded(id);

View file

@ -687,7 +687,10 @@ class SimpleHTMLCollection final : public nsSimpleContentList,
}
virtual uint32_t Length() override { return nsSimpleContentList::Length(); }
virtual Element* GetElementAt(uint32_t aIndex) override {
return mElements.SafeElementAt(aIndex)->AsElement();
if (nsIContent* content = mElements.SafeElementAt(aIndex)) {
return content->AsElement();
}
return nullptr;
}
virtual Element* GetFirstNamedElement(const nsAString& aName,

View file

@ -17,6 +17,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Maybe.h"
#include "mozilla/Span.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/BlobImpl.h"
@ -173,7 +174,8 @@ bool StructuredCloneBlob::Holder::ReadStructuredCloneInternal(
return false;
}
#endif
BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount);
BlobImpls().AppendElements(
Span(aHolder->BlobImpls()).Subspan(blobOffset, blobCount));
}
JSStructuredCloneData data(mStructuredCloneScope);

View file

@ -3583,6 +3583,7 @@ void nsRange::CreateOrUpdateCrossShadowBoundaryRangeIfNeeded(
// Nodes at least needs to be in the same document.
if (startNode && endNode &&
startNode->GetComposedDoc() != endNode->GetComposedDoc()) {
ResetCrossShadowBoundaryRange();
return;
}
@ -3597,6 +3598,13 @@ void nsRange::CreateOrUpdateCrossShadowBoundaryRangeIfNeeded(
return false;
}
// We don't allow ranges to span different NAC subtrees (because we don't
// notify when unbinding NAC roots historically). nsRange can already deal
// with the "same anonymous subtree" case.
if (aContainer->IsInNativeAnonymousSubtree()) {
return false;
}
// AbstractRange::GetClosestCommonInclusiveAncestor only supports
// Document and Content nodes.
return aContainer->IsDocument() || aContainer->IsContent();

View file

@ -14,6 +14,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/Encoding.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Maybe.h"
#include "mozilla/Preferences.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs_dom.h"
@ -3800,7 +3801,7 @@ bool HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
// Technically, per spec, a window always has a document. In Gecko, a
// sufficiently torn-down window might not, so check for that case. We're
// going to need a document to create an element.
Document* doc = window->GetExtantDoc();
RefPtr<Document> doc = window->GetExtantDoc();
if (!doc) {
rv.Throw(NS_ERROR_UNEXPECTED);
return false;
@ -3843,7 +3844,7 @@ bool HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
}
// Step 3.
CustomElementDefinition* definition =
RefPtr<CustomElementDefinition> definition =
registry->LookupCustomElementDefinition(aCx, newTarget);
if (!definition) {
rv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
@ -3943,6 +3944,21 @@ bool HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
// Steps 7 and 8.
JS::Rooted<JSObject*> desiredProto(aCx);
// Check which construction path we're taking before running any JS.
// This determines whether we need AutoConstructionDepth protection.
nsTArray<RefPtr<Element>>& constructionStack = definition->mConstructionStack;
const bool isDirectConstruction = constructionStack.IsEmpty();
// For direct construction (not upgrade), create AutoConstructionDepth before
// GetDesiredProto. This ensures mConstructionDepth is incremented before any
// re-entrant JS can run via Proxy traps, preventing desynchronization with
// mPrefixStack which may be pushed by nsContentUtils::NewXULOrHTMLElement.
mozilla::Maybe<AutoConstructionDepth> autoDepth;
if (isDirectConstruction) {
autoDepth.emplace(definition);
}
if (!GetDesiredProto(aCx, args, aProtoId, aCreator, &desiredProto)) {
return false;
}
@ -3953,14 +3969,12 @@ bool HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
// one branch and steps 9-12 on another branch, then common up the "return
// element" work.
RefPtr<Element> element;
nsTArray<RefPtr<Element>>& constructionStack = definition->mConstructionStack;
if (constructionStack.IsEmpty()) {
if (isDirectConstruction) {
// Step 8.
// Now we go to construct an element. We want to do this in global's
// realm, not caller realm (the normal constructor behavior),
// just in case those elements create JS things.
JSAutoRealm ar(aCx, global.Get());
AutoConstructionDepth acd(definition);
RefPtr<NodeInfo> nodeInfo = doc->NodeInfoManager()->GetNodeInfo(
definition->mLocalName, definition->mPrefixStack.LastElement(), ns,

View file

@ -580,7 +580,7 @@ bool TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec,
const auto& unpacking = unpackingRes.inspect();
const auto stride = unpacking.metrics.bytesPerRowStride;
// clang-format off
if (!ConvertIfNeeded(webgl, unpacking.state.rowLength,
if (!ConvertIfNeeded(webgl, unpacking.metrics.usedPixelsPerRow,
unpacking.metrics.totalRows,
format, uploadPtr, AutoAssertCast(stride),
format, AutoAssertCast(stride), &uploadPtr, &tempBuffer)) {
@ -1109,6 +1109,12 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
////
const auto surfSize = surf->GetSize();
if (uint32_t(surfSize.width) < size.x || uint32_t(surfSize.height) < size.y) {
gfxCriticalError() << "Source surface size too small for upload.";
return false;
}
WebGLTexelFormat srcFormat;
uint8_t srcBPP;
if (!GetFormatForSurf(surf, &srcFormat, &srcBPP)) {
@ -1133,7 +1139,7 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
const auto dstFormat = FormatForPackingInfo(dstPI);
const size_t dstBpp = BytesPerPixel(dstPI);
const size_t dstUsedBytesPerRow = dstBpp * surf->GetSize().width;
const size_t dstUsedBytesPerRow = dstBpp * surfSize.width;
size_t dstStride = dstFormat == srcFormat ? srcStride // Try To match
: dstUsedBytesPerRow;
@ -1164,7 +1170,7 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
const uint8_t* dstBegin = srcBegin;
UniqueBuffer tempBuffer;
// clang-format off
if (!ConvertIfNeeded(webgl, surf->GetSize().width, surf->GetSize().height,
if (!ConvertIfNeeded(webgl, surfSize.width, surfSize.height,
srcFormat, srcBegin, AutoAssertCast(srcStride),
dstFormat, AutoAssertCast(dstUnpacking.metrics.bytesPerRowStride), &dstBegin,
&tempBuffer)) {

View file

@ -2885,6 +2885,7 @@ webgl::ExplicitPixelPackingState::ForUseWith(
auto metrics = Metrics{};
metrics.usedSize = subrectSize;
metrics.usedPixelsPerRow = usedPixelsPerRow.value();
metrics.bytesPerPixel = BytesPerPixel(pi);
// -

View file

@ -1142,6 +1142,9 @@ struct ExplicitPixelPackingState final {
// ...aligned to ALIGNMENT.
size_t bytesPerRowStride = 0;
// SKIP_PIXELS+size.x
size_t usedPixelsPerRow = 0;
// structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
size_t totalRows = 0;

View file

@ -9,6 +9,9 @@
#include "ClientManager.h"
#include "ClientSource.h"
#include "MainThreadUtils.h"
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/dom/ClientsBinding.h"
#include "mozilla/dom/ServiceWorkerDescriptor.h"
#include "mozilla/ipc/BackgroundUtils.h"
@ -133,6 +136,13 @@ class ClientChannelHelper : public nsIInterfaceRequestor,
// If it's a cross-origin redirect then we discard the old reserved client
// and create a new one.
else {
// The partition-key, and in particular the foreign bit, can change on a
// cross-origin redirect so it is essential to update the anti-tracking
// info for the channel. This will happen in nsHttpChannel::AsyncOpen but
// that happens strictly after now, whereas we are sampling the principal
// now.
AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(aNewChannel);
nsCOMPtr<nsIPrincipal> foreignPartitionedPrincipal;
rv = StoragePrincipalHelper::GetPrincipal(
aNewChannel,

View file

@ -194,6 +194,12 @@ already_AddRefed<Promise> CredentialsContainer::Get(
return promise.forget();
}
if (aOptions.mMediation != CredentialMediationRequirement::Conditional &&
aOptions.mMediation != CredentialMediationRequirement::Optional &&
aOptions.mMediation != CredentialMediationRequirement::Required) {
return CreateAndRejectWithNotSupported(mParent, aRv);
}
EnsureWebAuthnHandler();
return mWebAuthnHandler->GetAssertion(aOptions.mPublicKey.Value(),
conditionallyMediated,
@ -269,6 +275,11 @@ already_AddRefed<Promise> CredentialsContainer::Create(
return CreateAndRejectWithNotAllowed(mParent, aRv);
}
if (aOptions.mMediation != CredentialMediationRequirement::Optional &&
aOptions.mMediation != CredentialMediationRequirement::Required) {
return CreateAndRejectWithNotSupported(mParent, aRv);
}
EnsureWebAuthnHandler();
return mWebAuthnHandler->MakeCredential(aOptions.mPublicKey.Value(),
aOptions.mSignal, aRv);

View file

@ -176,7 +176,7 @@ IPCResult FetchParent::RecvFetchOp(FetchOpArgs&& aArgs) {
self->mResponsePromises =
fetchService->Fetch(AsVariant(FetchService::WorkerFetchArgs(
{self->mRequest.clonePtr(), self->mPrincipalInfo,
self->mWorkerScript, self->mClientInfo, self->mController,
self->mWorkerScript, *self->mClientInfo, self->mController,
self->mCookieJarSettings, self->mNeedOnDataAvailable,
self->mCSPEventListener, self->mAssociatedBrowsingContextID,
self->mBackgroundEventTarget, self->mID,
@ -189,6 +189,7 @@ IPCResult FetchParent::RecvFetchOp(FetchOpArgs&& aArgs) {
fetchService->Fetch(AsVariant(FetchService::MainThreadFetchArgs({
self->mRequest.clonePtr(),
self->mPrincipalInfo,
*self->mClientInfo,
self->mCookieJarSettings,
self->mNeedOnDataAvailable,
self->mCSPEventListener,

View file

@ -271,8 +271,7 @@ RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() {
if (mArgsType == FetchArgsType::WorkerFetch) {
auto& args = mArgs.as<WorkerFetchArgs>();
mFetchDriver->SetWorkerScript(args.mWorkerScript);
MOZ_ASSERT(args.mClientInfo.isSome());
mFetchDriver->SetClientInfo(args.mClientInfo.ref());
mFetchDriver->SetClientInfo(args.mClientInfo);
mFetchDriver->SetController(args.mController);
if (args.mCSPEventListener) {
mFetchDriver->SetCSPEventListener(args.mCSPEventListener);
@ -285,6 +284,7 @@ RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() {
if (mArgsType == FetchArgsType::MainThreadFetch) {
auto& args = mArgs.as<MainThreadFetchArgs>();
mFetchDriver->SetClientInfo(args.mClientInfo);
mFetchDriver->SetIsThirdPartyContext(Some(args.mIsThirdPartyContext));
}

View file

@ -108,7 +108,7 @@ class FetchService final : public nsIObserver {
SafeRefPtr<InternalRequest> mRequest;
mozilla::ipc::PrincipalInfo mPrincipalInfo;
nsCString mWorkerScript;
Maybe<ClientInfo> mClientInfo;
ClientInfo mClientInfo;
Maybe<ServiceWorkerDescriptor> mController;
Maybe<net::CookieJarSettingsArgs> mCookieJarSettings;
bool mNeedOnDataAvailable;
@ -131,6 +131,7 @@ class FetchService final : public nsIObserver {
struct MainThreadFetchArgs {
SafeRefPtr<InternalRequest> mRequest;
mozilla::ipc::PrincipalInfo mPrincipalInfo;
ClientInfo mClientInfo;
Maybe<net::CookieJarSettingsArgs> mCookieJarSettings;
bool mNeedOnDataAvailable;
nsCOMPtr<nsICSPEventListener> mCSPEventListener;

View file

@ -1316,6 +1316,7 @@ class DatabaseConnection::UpdateRefcountFunction::FileInfoEntry final {
}
}
void DecBySavepointDelta() { mDelta -= mSavepointDelta; }
void ResetSavepointDelta() { mSavepointDelta = 0; }
SafeRefPtr<DatabaseFileInfo> ReleaseFileInfo() {
return std::move(mFileInfo);
}
@ -7583,6 +7584,7 @@ void DatabaseConnection::UpdateRefcountFunction::RollbackSavepoint() {
for (const auto& entry : mSavepointEntriesIndex.Values()) {
entry->DecBySavepointDelta();
entry->ResetSavepointDelta();
}
mInSavepoint = false;
@ -10548,8 +10550,8 @@ already_AddRefed<PBackgroundIDBCursorParent> TransactionBase::AllocCursor(
if (NS_AUUF_OR_WARN_IF(!objectStoreMetadata)) {
return nullptr;
}
if (aTrustParams && NS_AUUF_OR_WARN_IF(!VerifyRequestParams(
commonParams.optionalKeyRange()))) {
if (!aTrustParams && NS_AUUF_OR_WARN_IF(!VerifyRequestParams(
commonParams.optionalKeyRange()))) {
return nullptr;
}
direction = commonParams.direction();
@ -18974,7 +18976,8 @@ nsresult ObjectStoreAddOrPutRequestOp::DoDatabaseWork(
// Update index keys if primary key is preserved in child.
for (auto& updateInfo : mParams.indexUpdateInfos()) {
updateInfo.value().MaybeUpdateAutoIncrementKey(autoIncrementNum);
QM_TRY(
updateInfo.value().MaybeUpdateAutoIncrementKey(autoIncrementNum));
}
} else if (key.IsFloat()) {
double numericKey = key.ToFloat();

View file

@ -585,19 +585,34 @@ void Key::ReserveAutoIncrementKey(bool aFirstOfArray) {
mozilla::BigEndian::writeUint64(buffer, UINT64_MAX);
}
void Key::MaybeUpdateAutoIncrementKey(int64_t aKey) {
Result<Ok, nsresult> Key::MaybeUpdateAutoIncrementKey(int64_t aKey) {
if (mAutoIncrementKeyOffsets.IsEmpty()) {
return;
return Ok{};
}
static constexpr auto maxOffset =
KEY_MAXIMUM_BUFFER_LENGTH - sizeof(double) - 1;
for (uint32_t offset : mAutoIncrementKeyOffsets) {
if (offset > maxOffset) {
return Err(NS_ERROR_DOM_INDEXEDDB_KEY_ERR);
}
char* buffer;
MOZ_ALWAYS_TRUE(mBuffer.GetMutableData(&buffer));
const auto capacity = mBuffer.GetMutableData(&buffer);
MOZ_ALWAYS_TRUE(capacity);
if (offset + sizeof(double) > capacity) {
return Err(NS_ERROR_DOM_INDEXEDDB_KEY_ERR);
}
buffer += offset;
WriteDoubleToUint64(buffer, double(aKey));
}
TrimBuffer();
return Ok{};
}
void Key::WriteDoubleToUint64(char* aBuffer, double aValue) {

View file

@ -185,7 +185,7 @@ class Key {
void ReserveAutoIncrementKey(bool aFirstOfArray);
void MaybeUpdateAutoIncrementKey(int64_t aKey);
Result<Ok, nsresult> MaybeUpdateAutoIncrementKey(int64_t aKey);
private:
class MOZ_STACK_CLASS ArrayValueEncoder;

View file

@ -325,6 +325,7 @@ void MediaKeys::RejectPromise(PromiseId aId, ErrorResult&& aException,
this, aId, errorCodeAsInt);
return;
}
RefPtr<MediaKeys> keys(this);
// This promise could be a createSession or loadSession promise,
// so we might have a pending session waiting to be resolved into
@ -379,6 +380,7 @@ void MediaKeys::ResolvePromise(PromiseId aId) {
if (!promise) {
return;
}
RefPtr<MediaKeys> keys(this);
uint32_t token = 0;
if (!mPromiseIdToken.Get(aId, &token)) {

View file

@ -189,8 +189,10 @@ bool ClearKeyUtils::DecryptCbcs(const vector<uint8_t>& aKey,
/* static */
bool ClearKeyUtils::DecryptAES(const vector<uint8_t>& aKey,
vector<uint8_t>& aData, vector<uint8_t>& aIV) {
assert(aIV.size() == CENC_KEY_LEN);
assert(aKey.size() == CENC_KEY_LEN);
if (aKey.size() != CENC_KEY_LEN || aIV.size() != CENC_KEY_LEN) {
CK_LOGE("Key and IV size should be 16!");
return false;
}
PK11SlotInfo* slot = PK11_GetInternalKeySlot();
if (!slot) {

View file

@ -1200,7 +1200,7 @@ MediaResult MediaChangeMonitor::CreateDecoderAndInit(MediaRawData* aSample) {
return;
}
mDecodePromise.Reject(
mDecodePromise.RejectIfExists(
MediaResult(
aError.Code(),
RESULT_DETAIL("Unable to initialize decoder")),
@ -1215,7 +1215,7 @@ MediaResult MediaChangeMonitor::CreateDecoderAndInit(MediaRawData* aSample) {
mFlushPromise.Reject(aError, __func__);
return;
}
mDecodePromise.Reject(
mDecodePromise.RejectIfExists(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("Unable to create decoder")),
__func__);
@ -1259,12 +1259,12 @@ void MediaChangeMonitor::DecodeFirstSample(MediaRawData* aSample) {
[self, this](MediaDataDecoder::DecodedData&& aResults) {
mDecodePromiseRequest.Complete();
mPendingFrames.AppendElements(std::move(aResults));
mDecodePromise.Resolve(std::move(mPendingFrames), __func__);
mDecodePromise.ResolveIfExists(std::move(mPendingFrames), __func__);
mPendingFrames = DecodedData();
},
[self, this](const MediaResult& aError) {
mDecodePromiseRequest.Complete();
mDecodePromise.Reject(aError, __func__);
mDecodePromise.RejectIfExists(aError, __func__);
})
->Track(mDecodePromiseRequest);
}
@ -1323,7 +1323,7 @@ void MediaChangeMonitor::DrainThenFlushDecoder(MediaRawData* aPendingSample) {
mFlushPromise.Reject(aError, __func__);
return;
}
mDecodePromise.Reject(aError, __func__);
mDecodePromise.RejectIfExists(aError, __func__);
})
->Track(mDrainRequest);
}
@ -1367,7 +1367,7 @@ void MediaChangeMonitor::FlushThenShutdownDecoder(
return;
}
MOZ_ASSERT(NS_FAILED(rv));
mDecodePromise.Reject(rv, __func__);
mDecodePromise.RejectIfExists(rv, __func__);
return;
},
[] { MOZ_CRASH("Can't reach here'"); })
@ -1380,7 +1380,7 @@ void MediaChangeMonitor::FlushThenShutdownDecoder(
mFlushPromise.Reject(aError, __func__);
return;
}
mDecodePromise.Reject(aError, __func__);
mDecodePromise.RejectIfExists(aError, __func__);
})
->Track(mFlushRequest);
}

File diff suppressed because one or more lines are too long

View file

@ -187,3 +187,4 @@ load 1905234.html
load 1905231.webm
load 1917627.mp4
skip-if(Android) load audioworkletprocessor-recursion.html
load 2014824.html

View file

@ -229,7 +229,12 @@ class AutoResampler final {
MOZ_ASSERT(mResampler);
return mResampler;
}
void operator=(SpeexResamplerState* aResampler) { mResampler = aResampler; }
void operator=(SpeexResamplerState* aResampler) {
if (mResampler) {
speex_resampler_destroy(mResampler);
}
mResampler = aResampler;
}
private:
SpeexResamplerState* mResampler;
@ -564,6 +569,13 @@ void MediaDecodeTask::FinishDecode() {
}
mDecodeJob.mBuffer.mBuffer = std::move(newBuffers);
channelCount = audioData->mChannels;
// Don't bother draining the previous resampler for unexpected edge case.
if (sampleRate != destSampleRate) {
resampler = speex_resampler_init(channelCount, sampleRate, destSampleRate,
SPEEX_RESAMPLER_QUALITY_DEFAULT, nullptr);
speex_resampler_skip_zeros(resampler);
}
}
const AudioDataValue* bufferData =

View file

@ -900,6 +900,12 @@ nsresult WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType,
for (uint8_t i = 0; i < numPartitions; i++) {
uint32_t partition = partitions[i];
if (partition > length || partition < lastOffset) {
WEBM_DEBUG(
"Invalid partition offset: %u (length: %zu, lastOffset: %u)",
partition, length, lastOffset);
return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
}
uint32_t currentLength = partition - lastOffset;
if (encrypted) {
@ -910,8 +916,6 @@ nsresult WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType,
encrypted = !encrypted;
lastOffset = partition;
MOZ_ASSERT(lastOffset <= length);
}
// Add the data between the last offset and the end of the data.

View file

@ -855,6 +855,15 @@ int32_t WebrtcGmpVideoDecoder::Decode(const webrtc::EncodedImage& aInputImage,
}
void WebrtcGmpVideoDecoder::Decode_g(UniquePtr<GMPDecodeData>&& aDecodeData) {
CheckedInt<uint32_t> dataSize(aDecodeData->mImage.size());
dataSize -= 4;
if (!dataSize.isValid()) {
GMP_LOG_ERROR("%s: bad input size (%zu)!", __PRETTY_FUNCTION__,
aDecodeData->mImage.size());
mDecoderStatus = GMPInvalidArgErr;
return;
}
if (!mGMP) {
if (mInitting) {
// InitDone hasn't been called yet (race)

View file

@ -47,6 +47,7 @@
add_task(test_empty_credential_list);
add_task(test_credential_protection_policy_uv_optional_with_list);
add_task(test_credential_protection_policy_uv_required);
add_task(test_unsupported_mediation_requirements);
function requestGetAssertion(params) {
return navigator.credentials.get(params);
@ -80,6 +81,11 @@
is(aResult.code, DOMException.ABORT_ERR, "Expecting an AbortError");
}
function expectNotSupportedError(aResult) {
ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
return Promise.resolve();
}
// Set up a valid credential
async function test_setup_valid_credential() {
let publicKey = {
@ -293,6 +299,19 @@
setUserVerified(authenticatorId, true)
}
async function test_unsupported_mediation_requirements() {
let publicKey = {
challenge: gAssertionChallenge,
allowCredentials: [validCred]
};
for (const mediation of ["silent"]) {
await requestGetAssertion({publicKey, mediation})
.then(arrivingHereIsBad)
.catch(expectNotSupportedError);
}
}
</script>
</body>

View file

@ -78,6 +78,7 @@
add_task(test_no_unexpected_extensions);
add_task(test_cred_props_with_rk_required);
add_task(test_cred_props_with_rk_discouraged);
add_task(test_unsupported_mediation_requirements);
function arrivingHereIsGood(aResult) {
ok(true, "Good result! Received a: " + aResult);
@ -453,6 +454,17 @@
is(extensionResults.credProps?.rk, false, "rk is false");
}
async function test_unsupported_mediation_requirements() {
let makeCredentialOptions = {
rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
};
for (const mediation of ["conditional", "silent"]) {
await credm.create({publicKey: makeCredentialOptions, mediation})
.then(arrivingHereIsBad)
.catch(expectNotSupportedError);
}
}
</script>
</body>

View file

@ -50,6 +50,7 @@ enum CredentialMediationRequirement {
};
dictionary CredentialCreationOptions {
CredentialMediationRequirement mediation = "optional";
// This is taken from the partial definition in
// https://w3c.github.io/webauthn/#sctn-credentialcreationoptions-extension
[Pref="security.webauth.webauthn"]

View file

@ -0,0 +1,27 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
[
<!ENTITY bomb0 "bomb">
<!ENTITY bomb1 "&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;">
<!ENTITY bomb2 "&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;">
<!ENTITY bomb3 "&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;">
<!ENTITY bomb4 "&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;">
<!ENTITY bomb5 "&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;">
<!ENTITY bomb6 "&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;">
<!ENTITY bomb7 "&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;">
<!ENTITY bomb8 "&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;">
<!ENTITY bomb9 "&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;">
<!ENTITY bomb10 "&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;">]>
<html>
<body>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>
<div someAttr="&bomb10;"></div>

View file

@ -10,5 +10,6 @@ load 453278.html
load 803586.xhtml
load 994740-1.xhtml
load 1038887.xhtml
load 1192544.xhtml
load 1405878.xml
load 1523655.xml

View file

@ -2878,13 +2878,26 @@ void EditorBase::DispatchInputEvent() {
return;
}
RefPtr<DataTransfer> dataTransfer = GetInputEventDataTransfer();
const EditAction editAction = GetEditAction();
if (editAction == EditAction::eCancelComposition ||
editAction == EditAction::eCommitComposition) {
MOZ_ASSERT(!mComposition);
if (MOZ_UNLIKELY(!CanDispatchInputEventAfterCompositionEnd())) {
MOZ_LOG(gEventLog, LogLevel::Info,
("%p %s: Blocked to dispatch \"input\" event immediately after "
"eCompositionEnd",
this, mIsHTMLEditorClass ? "HTMLEditor" : "TextEditor"));
return;
}
}
const EditorInputType inputType = ToInputType(editAction);
mEditActionData->WillDispatchInputEvent();
MOZ_LOG(gEventLog, LogLevel::Info,
("%p %s: Dispatching \"input\" event: { inputType=\"%s\" }...", this,
mIsHTMLEditorClass ? "HTMLEditor" : "TextEditor",
ToString(ToInputType(GetEditAction())).c_str()));
ToString(inputType).c_str()));
DebugOnly<nsresult> rvIgnored = nsContentUtils::DispatchInputEvent(
targetElement, eEditorInput, ToInputType(GetEditAction()), this,
targetElement, eEditorInput, inputType, this,
dataTransfer ? InputEventOptions(dataTransfer,
InputEventOptions::NeverCancelable::No)
: InputEventOptions(GetInputEventData(),
@ -2892,7 +2905,7 @@ void EditorBase::DispatchInputEvent() {
MOZ_LOG(gEventLog, LogLevel::Debug,
("%p %s: Dispatched \"input\" event: { inputType=\"%s\" }", this,
mIsHTMLEditorClass ? "HTMLEditor" : "TextEditor",
ToString(ToInputType(GetEditAction())).c_str()));
ToString(inputType).c_str()));
mEditActionData->DidDispatchInputEvent();
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored),
@ -4215,8 +4228,10 @@ nsresult EditorBase::OnCompositionChange(
// NOTE: When the pref is enabled, the last `input` event which will be fired
// after `compositionend` won't be paired with corresponding `beforeinput`
// event.
else if (StaticPrefs::dom_input_events_dispatch_before_compositionend() &&
mDispatchInputEvent && !IsEditActionAborted()) {
else if (MOZ_LIKELY(
StaticPrefs::dom_input_events_dispatch_before_compositionend() &&
mDispatchInputEvent && !IsEditActionAborted() &&
CanDispatchInputEventBeforeCompositionEnd())) {
DispatchInputEvent();
}
@ -4297,6 +4312,56 @@ void EditorBase::OnCompositionEnd(
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
}
bool EditorBase::CanDispatchInputEventBeforeCompositionEnd() const {
Document* const doc = GetDocument();
if (NS_WARN_IF(!doc)) {
return false;
}
nsIPrincipal* const principal = doc->GetPrincipalForPrefBasedHacks();
if (!principal) {
return true;
}
constexpr static auto* kTextEditorPref =
"editor.texteditor.inputevent.hack.no_dispatch_before_compositionend";
constexpr static auto* kTextEditorAddlPref =
"editor.texteditor.inputevent.hack.no_dispatch_before_compositionend."
"addl";
constexpr static auto* kHTMLEditorPref =
"editor.htmleditor.inputevent.hack.no_dispatch_before_compositionend";
constexpr static auto* kHTMLEditorAddlPref =
"editor.htmleditor.inputevent.hack.no_dispatch_before_compositionend."
"addl";
return !principal->IsURIInPrefList(IsTextEditor() ? kTextEditorPref
: kHTMLEditorPref) &&
!principal->IsURIInPrefList(IsTextEditor() ? kTextEditorAddlPref
: kHTMLEditorAddlPref);
}
bool EditorBase::CanDispatchInputEventAfterCompositionEnd() const {
Document* const doc = GetDocument();
if (NS_WARN_IF(!doc)) {
return false;
}
nsIPrincipal* const principal = doc->GetPrincipalForPrefBasedHacks();
if (!principal) {
return true;
}
constexpr static auto* kTextEditorPref =
"editor.texteditor.inputevent.hack.no_dispatch_after_compositionend";
constexpr static auto* kTextEditorAddlPref =
"editor.texteditor.inputevent.hack.no_dispatch_after_compositionend."
"addl";
constexpr static auto* kHTMLEditorPref =
"editor.htmleditor.inputevent.hack.no_dispatch_after_compositionend";
constexpr static auto* kHTMLEditorAddlPref =
"editor.htmleditor.inputevent.hack.no_dispatch_after_compositionend."
"addl";
return !principal->IsURIInPrefList(IsTextEditor() ? kTextEditorPref
: kHTMLEditorPref) &&
!principal->IsURIInPrefList(IsTextEditor() ? kTextEditorAddlPref
: kHTMLEditorAddlPref);
}
bool EditorBase::WillHandleMouseButtonEvent(WidgetMouseEvent& aMouseEvent) {
MOZ_ASSERT(aMouseEvent.mMessage == eMouseDown ||
aMouseEvent.mMessage == eMouseUp);

View file

@ -2514,6 +2514,18 @@ class EditorBase : public nsIEditor,
*/
MOZ_CAN_RUN_SCRIPT void DispatchInputEvent();
/**
* Return true if it's NOT blocked by the pref to dispatch `input` event
* immediately before `compositionend`.
*/
[[nodiscard]] bool CanDispatchInputEventBeforeCompositionEnd() const;
/**
* Return true if it's NOT blocked by the pref to dispatch `input` event
* immediately after `compositionend`.
*/
[[nodiscard]] bool CanDispatchInputEventAfterCompositionEnd() const;
/**
* Called after a transaction is done successfully.
*/

View file

@ -622,6 +622,8 @@ support-files = ["file_sanitizer_on_paste.sjs"]
["test_select_all_without_body.html"]
support-files = ["file_select_all_without_body.html"]
["test_selectable_input_event_dispatching_for_compositionend.html"]
["test_selection_move_commands.html"]
support-files = ["!/gfx/layers/apz/test/mochitest/apz_test_utils.js"]

View file

@ -0,0 +1,108 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Test for block list of dispatching `input` event around `compositionend`</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
<script>
"use strict";
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(async () => {
for (const pref of [
"editor.texteditor.inputevent.hack.no_dispatch_before_compositionend",
"editor.htmleditor.inputevent.hack.no_dispatch_before_compositionend",
"editor.texteditor.inputevent.hack.no_dispatch_before_compositionend.addl",
"editor.htmleditor.inputevent.hack.no_dispatch_before_compositionend.addl",
"editor.texteditor.inputevent.hack.no_dispatch_after_compositionend",
"editor.htmleditor.inputevent.hack.no_dispatch_after_compositionend",
"editor.texteditor.inputevent.hack.no_dispatch_after_compositionend.addl",
"editor.htmleditor.inputevent.hack.no_dispatch_after_compositionend.addl",
]) {
for (const selector of ["input", "textarea", "div[contenteditable]"]) {
const element = document.querySelector(selector);
const isTextEditor = !selector.includes("[contenteditable]");
if (isTextEditor) {
element.value = "";
} else {
element.innerHTML = "<br>";
}
element.focus();
synthesizeCompositionChange({
composition: {
string: "abc",
clauses: [
{ length: 3, attr: COMPOSITION_ATTR_RAW_CLAUSE },
]
},
caret: {
start: 3,
length: 0,
}
});
const events = [];
function recordEvent(aEvent) {
events.push(aEvent);
}
element.addEventListener("compositionend", recordEvent);
element.addEventListener("input", recordEvent);
await SpecialPowers.pushPrefEnv({
set: [[pref, document.domain]],
});
synthesizeComposition({type: "compositioncommitasis"});
await SpecialPowers.clearUserPref(pref);
element.removeEventListener("compositionend", recordEvent);
element.removeEventListener("input", recordEvent);
const expectInputBeforeCompositionEnd =
!pref.startsWith(
`editor.${isTextEditor ? "texteditor" : "htmleditor"}.inputevent.hack.no_dispatch_before_compositionend`
);
const expectInputAfterCompositionEnd =
!pref.startsWith(
`editor.${isTextEditor ? "texteditor" : "htmleditor"}.inputevent.hack.no_dispatch_after_compositionend`
);
const expectedEvents = [];
if (expectInputBeforeCompositionEnd) {
expectedEvents.push({type: "input", inputType: "insertCompositionText", isComposing: true});
}
expectedEvents.push({type: "compositionend"});
if (expectInputAfterCompositionEnd) {
expectedEvents.push({type: "input", inputType: "insertCompositionText", isComposing: false});
}
function stringifyEvents(aEvents) {
function stringifyEvent(aEvent) {
return aEvent.type == "input"
? `input(inputType=${aEvent.inputType},isComposing=${aEvent.isComposing})`
: aEvent.type;
}
let ret = "[";
for (const e of aEvents) {
if (ret != "[") {
ret += ","
}
ret += stringifyEvent(e);
}
return ret + "]";
}
is(
stringifyEvents(events),
stringifyEvents(expectedEvents),
`Events should be dispatched as expected on ${selector} when ${pref} has current domain`
);
}
}
SimpleTest.finish();
});
</script>
</head>
<body>
<input>
<textarea></textarea>
<div contenteditable><br></div>
</body>
</html>

View file

@ -263,6 +263,8 @@ nsAuthGSSAPI::nsAuthGSSAPI(pType package) : mServiceFlags(REQ_DEFAULT) {
LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n"));
mComplete = false;
if (!gssLibrary && NS_FAILED(gssInit())) return;
mCtx = GSS_C_NO_CONTEXT;
@ -308,8 +310,6 @@ void nsAuthGSSAPI::Reset() {
}
mCtx = GSS_C_NO_CONTEXT;
mComplete = false;
mDelegationRequested = false;
mDelegationSupported = false;
}
/* static */
@ -358,7 +358,6 @@ nsAuthGSSAPI::GetNextToken(const void* inToken, uint32_t inTokenLen,
void** outToken, uint32_t* outTokenLen) {
OM_uint32 major_status, minor_status;
OM_uint32 req_flags = 0;
OM_uint32 ret_flags = 0;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
gss_buffer_t in_token_ptr = GSS_C_NO_BUFFER;
@ -373,22 +372,7 @@ nsAuthGSSAPI::GetNextToken(const void* inToken, uint32_t inTokenLen,
// If they've called us again after we're complete, reset to start afresh.
if (mComplete) Reset();
// Two-phase delegation logic
// Phase 1: Try authentication without delegation first
// Phase 2: Only retry with delegation if server supports it (ret_flags)
bool delegationConfigured = (mServiceFlags & REQ_DELEGATE) != 0;
if (delegationConfigured) {
if (!mDelegationRequested) {
// First attempt: don't request delegation yet
LOG(("First auth attempt without delegation"));
mDelegationRequested = true;
} else if (mDelegationSupported) {
// Second attempt: server supports delegation, now request it
LOG(("Retrying auth with delegation - server supports it"));
req_flags |= GSS_C_DELEG_FLAG;
}
}
if (mServiceFlags & REQ_DELEGATE) req_flags |= GSS_C_DELEG_FLAG;
if (mServiceFlags & REQ_MUTUAL_AUTH) req_flags |= GSS_C_MUTUAL_FLAG;
@ -442,7 +426,7 @@ nsAuthGSSAPI::GetNextToken(const void* inToken, uint32_t inTokenLen,
major_status = gss_init_sec_context_ptr(
&minor_status, GSS_C_NO_CREDENTIAL, &mCtx, server, mMechOID, req_flags,
GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, in_token_ptr, nullptr,
&output_token, &ret_flags, nullptr);
&output_token, nullptr, nullptr);
if (GSS_ERROR(major_status)) {
LogGssError(major_status, minor_status, "gss_init_sec_context() failed");
@ -450,27 +434,6 @@ nsAuthGSSAPI::GetNextToken(const void* inToken, uint32_t inTokenLen,
rv = NS_ERROR_FAILURE;
goto end;
}
// Check if server supports delegation (OK-AS-DELEGATE equivalent)
if (delegationConfigured && !mDelegationSupported &&
(ret_flags & GSS_C_DELEG_FLAG)) {
LOG(("Server supports delegation (GSS_C_DELEG_FLAG in ret_flags)"));
// If we completed without requesting delegation, but server supports it,
// we need to restart with delegation
if (major_status == GSS_S_COMPLETE && !(req_flags & GSS_C_DELEG_FLAG)) {
LOG(("Restarting authentication to request delegation"));
Reset();
// These flags get cleared by Reset().
// Set them again to make sure the next call sets GSS_C_DELEG_FLAG
mDelegationRequested = true;
mDelegationSupported = true;
gss_release_name_ptr(&minor_status, &server);
return GetNextToken(inToken, inTokenLen, outToken, outTokenLen);
}
}
if (major_status == GSS_S_COMPLETE) {
// Mark ourselves as being complete, so that if we're called again
// we know to start afresh.

View file

@ -54,11 +54,9 @@ class nsAuthGSSAPI final : public nsIAuthModule {
gss_ctx_id_t mCtx;
gss_OID mMechOID;
nsCString mServiceName;
uint32_t mServiceFlags = REQ_DEFAULT;
uint32_t mServiceFlags;
nsString mUsername;
bool mComplete = false;
bool mDelegationRequested = false;
bool mDelegationSupported = false;
bool mComplete;
};
#endif /* nsAuthGSSAPI_h__ */

View file

@ -52,7 +52,18 @@ void convolve_vertically_avx2(
};
int i = 0;
for (; i < filterLen / 2 * 2; i += 2) {
if (i < filterLen && (reinterpret_cast<uintptr_t>(filter) & 2) != 0) {
// _mm256_set1_epi32 may generate instructions that require 4-byte align
// for the memory load. ConvolutionFixed is 2 bytes, so a random offset
// into the filter array might be only 2-byte aligned. Process the first
// entry individually so that subsequent blocks will be 4-byte aligned.
convolve_16_pixels(
_mm256_set1_epi32(*(const int16_t*)(filter + i)),
_mm256_loadu_si256((const __m256i*)(srcRows[i] + x * 4)),
_mm256_setzero_si256());
i++;
}
for (; i + 1 < filterLen; i += 2) {
convolve_16_pixels(
_mm256_set1_epi32(*(const int32_t*)(filter + i)),
_mm256_loadu_si256((const __m256i*)(srcRows[i + 0] + x * 4)),

View file

@ -1843,20 +1843,28 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot(
TimeStamp start = TimeStamp::Now();
MOZ_ASSERT(bufferTexture->GetBufferDescriptor().type() ==
BufferDescriptor::TRGBDescriptor);
DebugOnly<uint32_t> stride = ImageDataSerializer::GetRGBStride(
bufferTexture->GetBufferDescriptor().get_RGBDescriptor());
if (bufferTexture->GetBufferDescriptor().type() !=
BufferDescriptor::TRGBDescriptor) {
return IPC_FAIL_NO_REASON(this);
}
uint8_t* buffer = bufferTexture->GetBuffer();
MOZ_ASSERT(buffer);
if (!buffer) {
return IPC_FAIL_NO_REASON(this);
}
IntSize size = bufferTexture->GetSize();
MOZ_ASSERT(buffer);
// For now the only formats we get here are RGBA and BGRA, and code below is
// assuming a bpp of 4. If we allow other formats, the code needs adjusting
// accordingly.
MOZ_ASSERT(BytesPerPixel(bufferTexture->GetFormat()) == 4);
uint32_t buffer_size = size.width * size.height * 4;
if (BytesPerPixel(bufferTexture->GetFormat()) != 4) {
return IPC_FAIL_NO_REASON(this);
}
// Assert the stride of the buffer is what webrender expects
MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
uint32_t buffer_size = size.width * size.height * 4;
FlushSceneBuilds();
FlushFrameGeneration(wr::RenderReasons::SNAPSHOT);

View file

@ -3542,6 +3542,14 @@ void gfxPlatform::ReInitFrameRate(const char* aPrefIgnored,
gPlatform->mVsyncDispatcher->SetVsyncSource(vsyncSource);
}
/* static */
void gfxPlatform::ResetHardwareVsyncSource() {
if (gPlatform->mGlobalHardwareVsyncSource) {
gPlatform->mGlobalHardwareVsyncSource->Shutdown();
gPlatform->mGlobalHardwareVsyncSource = nullptr;
}
}
const char* gfxPlatform::GetAzureCanvasBackend() const {
BackendType backend{};

View file

@ -695,6 +695,12 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
*/
static void ReInitFrameRate(const char* aPrefIgnored, void* aDataIgnored);
/**
* Reset the global hardware vsync source. The next call to ReInitFrameRate
* will attempt to reestablish it, and fall back to software if needed.
*/
static void ResetHardwareVsyncSource();
/**
* Update force subpixel AA quality setting (called after pref
* changes).

View file

@ -8,6 +8,7 @@
#include "gfxQuartzSurface.h"
#include "mozilla/DataMutex.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "gfxMacFont.h"
#include "gfxCoreTextShaper.h"
@ -734,33 +735,48 @@ class OSXVsyncSource final : public VsyncSource {
OSXVsyncSource() : mDisplayLink(nullptr, "OSXVsyncSource::mDisplayLink") {
MOZ_ASSERT(NS_IsMainThread());
mTimer = NS_NewTimer();
CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback,
this);
CGError err = CGDisplayRegisterReconfigurationCallback(
DisplayReconfigurationCallback, this);
if (err != kCGErrorSuccess) {
gfxWarning() << "Failed to register display reconfiguration callback";
// We're in a tricky situation. Without a working reconfiguration
// callback, we might fail to recover from sleep. Best to early exit
// without creating a display link, and fall back to software vsync.
return;
}
CreateDisplayLink();
auto displayLink = mDisplayLink.Lock();
if (!*displayLink) {
gfxWarning()
<< "Could not create a display link during construction. This is "
"unrecoverable. We'll fallback to software vsync.";
}
}
virtual ~OSXVsyncSource() {
MOZ_ASSERT(NS_IsMainThread());
CGDisplayRemoveReconfigurationCallback(DisplayReconfigurationCallback,
this);
DisableVsync();
DestroyDisplayLink();
Shutdown();
}
static void RetryCreateDisplayLink(nsITimer* aTimer, void* aOsxVsyncSource) {
static void RetryCreateDisplayLinkAndEnableVsync(nsITimer* aTimer,
void* aOsxVsyncSource) {
MOZ_ASSERT(NS_IsMainThread());
OSXVsyncSource* osxVsyncSource =
static_cast<OSXVsyncSource*>(aOsxVsyncSource);
MOZ_ASSERT(osxVsyncSource);
osxVsyncSource->DisableVsync();
osxVsyncSource->DestroyDisplayLink();
osxVsyncSource->CreateDisplayLink();
}
static void RetryEnableVsync(nsITimer* aTimer, void* aOsxVsyncSource) {
MOZ_ASSERT(NS_IsMainThread());
OSXVsyncSource* osxVsyncSource =
static_cast<OSXVsyncSource*>(aOsxVsyncSource);
MOZ_ASSERT(osxVsyncSource);
osxVsyncSource->EnableVsync();
if (!osxVsyncSource->IsVsyncEnabled()) {
gfxWarning() << "Display reconfiguration vsync has failed; giving up.";
osxVsyncSource->Shutdown();
gfxPlatform::ResetHardwareVsyncSource();
gfxPlatform::ReInitFrameRate(nullptr, nullptr);
}
}
void CreateDisplayLink() {
@ -774,6 +790,11 @@ class OSXVsyncSource final : public VsyncSource {
// with all displays running on the computer But if we have different
// monitors at different display rates, we may hit issues.
CVReturn retval = CVDisplayLinkCreateWithActiveCGDisplays(&*displayLink);
if (!*displayLink) {
gfxWarning()
<< "Could not create a display link with all active displays.";
return;
}
// Workaround for bug 1201401: CVDisplayLinkCreateWithCGDisplays()
// (called by CVDisplayLinkCreateWithActiveCGDisplays()) sometimes
@ -789,37 +810,18 @@ class OSXVsyncSource final : public VsyncSource {
retval = kCVReturnInvalidDisplay;
}
if (!*displayLink || (retval != kCVReturnSuccess)) {
NS_WARNING(
"Could not create a display link with all active displays. "
"Retrying");
if (*displayLink) {
CVDisplayLinkRelease(*displayLink);
*displayLink = nullptr;
}
// bug 1142708 - When coming back from sleep,
// or when changing displays, active displays may not be ready yet,
// even if listening for the kIOMessageSystemHasPoweredOn event
// from OS X sleep notifications.
// Active displays are those that are drawable.
// bug 1144638 - When changing display configurations and getting
// notifications from CGDisplayReconfigurationCallBack, the
// callback gets called twice for each active display
// so it's difficult to know when all displays are active.
// Instead, try again soon. The delay is arbitrary. 100ms chosen
// because on a late 2013 15" retina, it takes about that
// long to come back up from sleep.
uint32_t delay = 100;
mTimer->InitWithNamedFuncCallback(RetryCreateDisplayLink, this, delay,
nsITimer::TYPE_ONE_SHOT,
"RetryCreateDisplayLink");
if (retval != kCVReturnSuccess) {
gfxWarning()
<< "Display link was created, but is malformed; destroying it.";
CVDisplayLinkRelease(*displayLink);
*displayLink = nullptr;
return;
}
if (CVDisplayLinkSetOutputCallback(*displayLink, &VsyncCallback, this) !=
kCVReturnSuccess) {
NS_WARNING("Could not set displaylink output callback");
gfxWarning()
<< "Could not set display link output callback; destroying it.";
CVDisplayLinkRelease(*displayLink);
*displayLink = nullptr;
}
@ -842,20 +844,20 @@ class OSXVsyncSource final : public VsyncSource {
auto displayLink = mDisplayLink.Lock();
if (!*displayLink) {
NS_WARNING("No display link available when starting vsync");
gfxWarning() << "No display link available when starting vsync.";
return;
}
mPreviousTimestamp = TimeStamp::Now();
if (CVDisplayLinkStart(*displayLink) != kCVReturnSuccess) {
NS_WARNING("Could not activate the display link");
gfxWarning() << "Could not activate the display link.";
return;
}
CVTime vsyncRate =
CVDisplayLinkGetNominalOutputVideoRefreshPeriod(*displayLink);
if (vsyncRate.flags & kCVTimeIsIndefinite) {
NS_WARNING("Could not get vsync rate, setting to 60.");
gfxWarning() << "Could not get vsync rate, setting to 60.";
mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
} else {
int64_t timeValue = vsyncRate.timeValue;
@ -892,8 +894,12 @@ class OSXVsyncSource final : public VsyncSource {
void Shutdown() override {
MOZ_ASSERT(NS_IsMainThread());
mTimer->Cancel();
mTimer = nullptr;
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
CGDisplayRemoveReconfigurationCallback(DisplayReconfigurationCallback,
this);
DisableVsync();
DestroyDisplayLink();
}
@ -950,10 +956,12 @@ class OSXVsyncSource final : public VsyncSource {
// Check if we actually succeeded in enabling vsync, and if we didn't,
// retry one time.
if (!IsVsyncEnabled()) {
gfxWarning()
<< "Display reconfiguration vsync has failed; retrying one time.";
uint32_t delay = 100;
mTimer->InitWithNamedFuncCallback(RetryCreateDisplayLink, this, delay,
nsITimer::TYPE_ONE_SHOT,
"RetryEnableVsync");
mTimer->InitWithNamedFuncCallback(
RetryCreateDisplayLinkAndEnableVsync, this, delay,
nsITimer::TYPE_ONE_SHOT, "RetryCreateDisplayLinkAndEnableVsync");
}
}
}
@ -1007,8 +1015,8 @@ gfxPlatformMac::CreateGlobalHardwareVsyncSource() {
RefPtr<VsyncSource> osxVsyncSource = new OSXVsyncSource();
osxVsyncSource->EnableVsync();
if (!osxVsyncSource->IsVsyncEnabled()) {
NS_WARNING(
"OS X Vsync source not enabled. Falling back to software vsync.");
gfxWarning()
<< "OS X Vsync source not enabled. Falling back to software vsync.";
return GetSoftwareVsyncSource();
}

View file

@ -96,6 +96,11 @@ ConvertYCbCrToRGB32(const uint8_t* y_buf,
YUVColorSpace yuv_color_space,
ColorRange color_range,
RGB32Type rgb32_type) {
if (pic_x < 0 || pic_y < 0 || y_pitch < 0 || uv_pitch < 0 || rgb_pitch < 0) {
NS_WARNING("Negative origin or pitch is unsupported");
return NS_ERROR_NOT_IMPLEMENTED;
}
// Deprecated function's conversion is accurate.
// libyuv converion is a bit inaccurate to get performance. It dynamically
// calculates RGB from YUV to use simd. In it, signed byte is used for

View file

@ -206,7 +206,11 @@ nsresult SourceBuffer::Compact() {
if (capacity == MAX_CHUNK_CAPACITY) {
size_t lastLength = mChunks.LastElement().Length();
if (lastLength != capacity) {
mChunks.LastElement().SetCapacity(lastLength);
if (lastLength == 0) {
mChunks.RemoveLastElement();
} else {
mChunks.LastElement().SetCapacity(lastLength);
}
}
return NS_OK;
}

View file

@ -419,6 +419,10 @@ class SourceBuffer final {
bool SetCapacity(size_t aCapacity) {
MOZ_ASSERT(mData, "Allocation failed but nobody checked for it");
MOZ_ASSERT(aCapacity > 0, "zero sized resize");
if (aCapacity == 0) {
return false;
}
char* data = static_cast<char*>(realloc(mData, aCapacity));
if (!data) {
return false;

View file

@ -139,13 +139,19 @@ Orientation GetImageOrientation(const Mp4parseAvifInfo& aInfo) {
}
bool AVIFDecoderStream::ReadAt(int64_t offset, void* data, size_t size,
size_t* bytes_read) {
size = std::min(size, size_t(mBuffer->length() - offset));
if (size <= 0) {
CheckedInt<size_t> checkedOffset(offset);
if (!checkedOffset.isValid() || offset < 0 ||
checkedOffset.value() >= mBuffer->length()) {
return false;
}
CheckedInt<size_t> endPoint = checkedOffset + size;
if (!endPoint.isValid() || endPoint.value() > mBuffer->length()) {
return false;
}
memcpy(data, mBuffer->begin() + offset, size);
size = std::min<size_t>(size, mBuffer->length() - checkedOffset.value());
memcpy(data, mBuffer->begin() + checkedOffset.value(), size);
*bytes_read = size;
return true;
}
@ -158,11 +164,14 @@ bool AVIFDecoderStream::Length(int64_t* size) {
const uint8_t* AVIFDecoderStream::GetContiguousAccess(int64_t aOffset,
size_t aSize) {
if (aOffset + aSize >= mBuffer->length()) {
CheckedInt<size_t> checkedOffset(aOffset);
CheckedInt<size_t> endPoint = checkedOffset + aSize;
if (!checkedOffset.isValid() || !endPoint.isValid() ||
endPoint.value() > mBuffer->length()) {
return nullptr;
}
return mBuffer->begin() + aOffset;
return mBuffer->begin() + checkedOffset.value();
}
AVIFParser::~AVIFParser() {

View file

@ -21,8 +21,8 @@
namespace js {
namespace gc {
JS_PUBLIC_API void TraceRealm(JSTracer* trc, JS::Realm* realm,
const char* name);
JS_PUBLIC_API void TraceRealmRoot(JSTracer* trc, JS::Realm* realm,
const char* name);
} // namespace gc
} // namespace js
@ -34,7 +34,7 @@ template <>
struct GCPolicy<Realm*> : public NonGCPointerPolicy<Realm*> {
static void trace(JSTracer* trc, Realm** vp, const char* name) {
if (*vp) {
::js::gc::TraceRealm(trc, *vp, name);
::js::gc::TraceRealmRoot(trc, *vp, name);
}
}
};

View file

@ -36,6 +36,7 @@
#include "vm/Compartment-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/Realm-inl.h"
using namespace js;
@ -1451,6 +1452,7 @@ bool js::atomics_notify_impl(JSContext* cx, SharedArrayRawBuffer* sarb,
// avoid mutex ordering problems.
RootedValue resultMsg(cx, StringValue(cx->names().ok));
for (uint32_t i = 0; i < promisesToResolve.length(); i++) {
AutoRealm ar(cx, promisesToResolve[i]);
if (!PromiseObject::resolve(cx, promisesToResolve[i], resultMsg)) {
MOZ_ASSERT(cx->isThrowingOutOfMemory() || cx->isThrowingOverRecursed());
return false;

View file

@ -913,8 +913,9 @@ bool ModuleObject::isInstance(HandleValue value) {
}
bool ModuleObject::hasCyclicModuleFields() const {
// This currently only returns false if we GC during initialization.
return !getReservedSlot(CyclicModuleFieldsSlot).isUndefined();
bool result = !getReservedSlot(CyclicModuleFieldsSlot).isUndefined();
MOZ_ASSERT_IF(result, !hasSyntheticModuleFields());
return result;
}
CyclicModuleFields* ModuleObject::cyclicModuleFields() {
@ -1496,7 +1497,9 @@ bool ModuleObject::createSyntheticEnvironment(JSContext* cx,
return false;
}
MOZ_ASSERT(env->shape()->propMapLength() == values.length());
// We expect one property per synthetic value plus one for the *namespace*
// binding.
MOZ_ASSERT(env->shape()->propMapLength() == values.length() + 1);
for (uint32_t i = 0; i < values.length(); i++) {
env->setAliasedBinding(env->firstSyntheticValueSlot() + i, values[i]);

View file

@ -1058,7 +1058,7 @@ static constexpr auto AsciiRegExpEscapeMap() {
*/
template <typename CharT>
[[nodiscard]] static bool EncodeForRegExpEscape(
mozilla::Span<const CharT> chars, JSStringBuilder& sb) {
JSContext* cx, mozilla::Span<const CharT> chars, JSStringBuilder& sb) {
MOZ_ASSERT(sb.empty());
const size_t length = chars.size();
@ -1075,7 +1075,7 @@ template <typename CharT>
// Initial scan to determine if escape sequences are needed and to compute
// the output length.
size_t outLength = length;
mozilla::CheckedInt<size_t> outLength = length;
// Leading Ascii alpha-numeric character is hex-escaped.
size_t scanStart = 0;
@ -1115,12 +1115,16 @@ template <typename CharT>
outLength += UnicodeEscapeAddLength;
}
}
if (!outLength.isValid()) {
ReportAllocationOverflow(cx);
return false;
}
// Return if no escape sequences are needed.
if (outLength == length) {
if (outLength.value() == length) {
return true;
}
MOZ_ASSERT(outLength > length);
MOZ_ASSERT(outLength.value() > length);
// Inflating is fallible, so we have to convert to two-byte upfront.
if constexpr (std::is_same_v<CharT, char16_t>) {
@ -1130,7 +1134,7 @@ template <typename CharT>
}
// Allocate memory for the output using the final length.
if (!sb.reserve(outLength)) {
if (!sb.reserve(outLength.value())) {
return false;
}
@ -1230,19 +1234,20 @@ template <typename CharT>
appendUnescaped(length);
}
MOZ_ASSERT(sb.length() == outLength, "all characters were written");
MOZ_ASSERT(sb.length() == outLength.value(), "all characters were written");
return true;
}
[[nodiscard]] static bool EncodeForRegExpEscape(JSLinearString* string,
[[nodiscard]] static bool EncodeForRegExpEscape(JSContext* cx,
JSLinearString* string,
JSStringBuilder& sb) {
JS::AutoCheckCannotGC nogc;
if (string->hasLatin1Chars()) {
auto chars = mozilla::Span(string->latin1Range(nogc));
return EncodeForRegExpEscape(chars, sb);
return EncodeForRegExpEscape(cx, chars, sb);
}
auto chars = mozilla::Span(string->twoByteRange(nogc));
return EncodeForRegExpEscape(chars, sb);
return EncodeForRegExpEscape(cx, chars, sb);
}
/**
@ -1266,7 +1271,7 @@ static bool regexp_escape(JSContext* cx, unsigned argc, Value* vp) {
// Step 2-5.
JSStringBuilder sb(cx);
if (!EncodeForRegExpEscape(string, sb)) {
if (!EncodeForRegExpEscape(cx, string, sb)) {
return false;
}

View file

@ -6180,6 +6180,14 @@ static bool Deserialize(JSContext* cx, unsigned argc, Value* vp) {
}
}
if (scope > JS::StructuredCloneScope::SameProcess &&
(policy.areIntraClusterClonableSharedObjectsAllowed() ||
policy.areSharedMemoryObjectsAllowed())) {
JS_ReportErrorASCII(
cx, "deserialize in DifferentProcess scope cannot allow shared memory");
return false;
}
// Clone buffer was already consumed?
if (!obj->data()) {
JS_ReportErrorASCII(cx,

View file

@ -24,3 +24,47 @@ assertEq(ex.toString(),
`TypeError: The SharedArrayBuffer object cannot be serialized. The ` +
`Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP ` +
`headers can be used to enable this.`);
try {
const s = serialize([sab], undefined, { scope: "DifferentProcess", SharedArrayBuffer: "allow" });
deserialize(s, { scope: "DifferentProcess" });
assertEq("threw exception?", true);
} catch (e) {
ex = e;
}
assertEq(ex.toString().includes("Policy object must forbid cloning shared memory objects cross-process"), true);
// Can't deserialize a SameProcess buffer when only allowing DifferentProcess scope.
try {
const s = serialize([sab], undefined, { SharedArrayBuffer: "allow" });
deserialize(s, { scope: "DifferentProcess" });
assertEq("threw exception?", true);
} catch (e) {
ex = e;
}
assertEq(ex.toString().includes("incompatible structured clone scope"), true);
// If a buffer is tampered with, it can only be deserialized as DifferentProcess.
try {
const s = serialize([sab], undefined, { SharedArrayBuffer: "allow" });
const s2 = serialize([sab], undefined, { SharedArrayBuffer: "allow" });
const ta = new Uint32Array(s.arraybuffer);
ta[2] = 2; // DifferentProcess
// synthetic buffer! Forces scope to DifferentProcess despite what we say below.
s2.clonebuffer = ta.buffer;
const result = deserialize(s2, { SharedArrayBuffer: "allow", scope: "SameProcess" });
assertEq("threw exception?", true);
} catch (e) {
ex = e;
}
assertEq(ex.toString().includes("Cannot use less restrictive scope"), true);
// You can't deserialize with both scope=DifferentProcess and allowing shared memory.
try {
const s = serialize([sab], undefined, { SharedArrayBuffer: "allow" });
const result = deserialize(s, { SharedArrayBuffer: "allow", scope: "DifferentProcess" });
assertEq("threw exception?", true);
} catch (e) {
ex = e;
}
assertEq(ex.toString().includes("deserialize in DifferentProcess scope cannot allow shared memory"), true);

View file

@ -42,7 +42,7 @@ for ( let memtype of memtypes ) {
// Serialization and deserialization of shared memories work:
let mem2 = deserialize(serialize(mem1, [], {SharedArrayBuffer: 'allow'}), {SharedArrayBuffer: 'allow'});
let mem2 = deserialize(serialize(mem1, [], {SharedArrayBuffer: 'allow'}), {SharedArrayBuffer: 'allow', scope: 'SameProcess'});
assertEq(mem2 instanceof WebAssembly.Memory, true);
let buf2 = mem2.buffer;
assertEq(buf2 instanceof SharedArrayBuffer, true);
@ -102,6 +102,6 @@ for ( let memtype of memtypes ) {
let buf = mem.buffer;
let clonedbuf = serialize(buf, [], {SharedArrayBuffer: 'allow'});
mem.grow(Idx(memtype, 1));
let buf2 = deserialize(clonedbuf, {SharedArrayBuffer: 'allow'});
let buf2 = deserialize(clonedbuf, {SharedArrayBuffer: 'allow', scope: 'SameProcess'});
assertEq(buf.byteLength, buf2.byteLength);
}

View file

@ -2980,14 +2980,23 @@ void BaselineCacheIRCompiler::pushArguments(Register argcReg,
Register scratch, Register scratch2,
CallFlags flags, uint32_t argcFixed,
bool isJitCall) {
bool isConstructing = flags.isConstructing();
// Push the formal arguments, and possibly `this` and/or `callee`.
// There are three cases:
// 1. Non-scripted call: all arguments are pushed here.
// 2. Scripted call: all arguments except `callee` are pushed here. `callee`
// must be passed as a CalleeToken, and is pushed below.
// 3. Scripted constructor: only formal arguments are pushed here. We must
// push a new `this` value using createThis, and then push `callee` as
// a CalleeToken. Note that constructors must be Standard or Spread.
switch (flags.getArgFormat()) {
case CallFlags::Standard:
pushStandardArguments(argcReg, scratch, scratch2, argcFixed, isJitCall,
flags.isConstructing());
isConstructing);
break;
case CallFlags::Spread:
pushArrayArguments(argcReg, scratch, scratch2, isJitCall,
flags.isConstructing());
pushArrayArguments(argcReg, scratch, scratch2, isJitCall, isConstructing);
break;
case CallFlags::FunCall:
pushFunCallArguments(argcReg, calleeReg, scratch, scratch2, argcFixed,
@ -3006,6 +3015,16 @@ void BaselineCacheIRCompiler::pushArguments(Register argcReg,
default:
MOZ_CRASH("Invalid arg format");
}
if (isJitCall) {
if (isConstructing) {
createThis(argcReg, calleeReg, scratch, scratch2, flags);
}
// Note that we use Push, not push, so that callJit will align the stack
// properly on ARM.
masm.PushCalleeToken(calleeReg, isConstructing);
}
}
void BaselineCacheIRCompiler::pushStandardArguments(
@ -3013,11 +3032,16 @@ void BaselineCacheIRCompiler::pushStandardArguments(
bool isJitCall, bool isConstructing) {
MOZ_ASSERT(enteredStubFrame_);
// The arguments to the call IC are pushed on the stack left-to-right.
// Our calling conventions want them right-to-left in the callee, so
// we duplicate them on the stack in reverse order.
// The arguments to the call IC were pushed on the stack from left to right,
// meaning that the first argument is at the highest address and the last
// argument is at the lowest address. Our callee needs them to be in the
// opposite order, so we duplicate them now.
bool shouldCopyCallee = !isJitCall;
bool shouldCopyThis = shouldCopyCallee || !isConstructing;
bool shouldCopyNewTarget = isConstructing;
int additionalArgc = shouldCopyCallee + shouldCopyThis + shouldCopyNewTarget;
int additionalArgc = 1 + !isJitCall + isConstructing;
if (argcFixed < MaxUnrolledArgCopy) {
#ifdef DEBUG
Label ok;
@ -3029,7 +3053,8 @@ void BaselineCacheIRCompiler::pushStandardArguments(
size_t realArgc = argcFixed + additionalArgc;
if (isJitCall) {
masm.alignJitStackBasedOnNArgs(realArgc, /*countIncludesThis = */ true);
masm.alignJitStackBasedOnNArgs(realArgc,
/*countIncludesThis = */ shouldCopyThis);
}
for (size_t i = 0; i < realArgc; ++i) {
@ -3057,7 +3082,8 @@ void BaselineCacheIRCompiler::pushStandardArguments(
// Align the stack such that the JitFrameLayout is aligned on the
// JitStackAlignment.
if (isJitCall) {
masm.alignJitStackBasedOnNArgs(countReg, /*countIncludesThis = */ true);
masm.alignJitStackBasedOnNArgs(countReg,
/*countIncludesThis = */ shouldCopyThis);
}
// Push all values, starting at the last one.
@ -3120,15 +3146,15 @@ void BaselineCacheIRCompiler::pushArrayArguments(Register argcReg,
masm.jump(&copyStart);
masm.bind(&copyDone);
// Push |this|.
size_t thisvOffset =
BaselineStubFrameLayout::Size() + (1 + isConstructing) * sizeof(Value);
masm.pushValue(Address(FramePointer, thisvOffset));
bool shouldPushCallee = !isJitCall;
bool shouldPushThis = shouldPushCallee || !isConstructing;
// Push |callee| if needed.
if (!isJitCall) {
size_t calleeOffset =
BaselineStubFrameLayout::Size() + (2 + isConstructing) * sizeof(Value);
if (shouldPushThis) {
size_t thisvOffset = arrayOffset + sizeof(Value);
masm.pushValue(Address(FramePointer, thisvOffset));
}
if (shouldPushCallee) {
size_t calleeOffset = arrayOffset + 2 * sizeof(Value);
masm.pushValue(Address(FramePointer, calleeOffset));
}
}
@ -3355,14 +3381,7 @@ void BaselineCacheIRCompiler::pushBoundFunctionArguments(
}
}
if (isConstructing) {
// Push the |this| Value. This is either the object we allocated or the
// JS_UNINITIALIZED_LEXICAL magic value. It's stored in the BaselineFrame,
// so skip past the stub frame, (unbound) arguments and newTarget.
BaseValueIndex thisAddress(FramePointer, argcReg,
BaselineStubFrameLayout::Size() + sizeof(Value));
masm.pushValue(thisAddress, scratch);
} else {
if (!isConstructing) {
// Push the bound |this|.
Address boundThis(calleeReg, BoundFunctionObject::offsetOfBoundThisSlot());
masm.pushValue(boundThis);
@ -3578,15 +3597,16 @@ bool BaselineCacheIRCompiler::emitCallClassHook(ObjOperandId calleeId,
// and unboxes an object from a specific slot.
void BaselineCacheIRCompiler::loadStackObject(ArgumentKind kind,
CallFlags flags, Register argcReg,
Register dest) {
Register dest,
uint32_t extraArgs) {
MOZ_ASSERT(enteredStubFrame_);
bool addArgc = false;
int32_t slotIndex = GetIndexOfArgument(kind, flags, &addArgc);
if (addArgc) {
int32_t slotOffset =
slotIndex * sizeof(JS::Value) + BaselineStubFrameLayout::Size();
int32_t slotOffset = (slotIndex - extraArgs) * sizeof(JS::Value) +
BaselineStubFrameLayout::Size();
BaseValueIndex slotAddr(FramePointer, argcReg, slotOffset);
masm.unboxObject(slotAddr, dest);
} else {
@ -3597,50 +3617,33 @@ void BaselineCacheIRCompiler::loadStackObject(ArgumentKind kind,
}
}
template <typename T>
void BaselineCacheIRCompiler::storeThis(const T& newThis, Register argcReg,
CallFlags flags) {
switch (flags.getArgFormat()) {
case CallFlags::Standard: {
BaseValueIndex thisAddress(
FramePointer,
argcReg, // Arguments
1 * sizeof(Value) + // NewTarget
BaselineStubFrameLayout::Size()); // Stub frame
masm.storeValue(newThis, thisAddress);
} break;
case CallFlags::Spread: {
Address thisAddress(FramePointer,
2 * sizeof(Value) + // Arg array, NewTarget
BaselineStubFrameLayout::Size()); // Stub frame
masm.storeValue(newThis, thisAddress);
} break;
default:
MOZ_CRASH("Invalid arg format for scripted constructor");
}
}
/*
* Scripted constructors require a |this| object to be created prior to the
* call. When this function is called, the stack looks like (bottom->top):
*
* [..., Callee, ThisV, Arg0V, ..., ArgNV, NewTarget, StubFrameHeader]
*
* At this point, |ThisV| is JSWhyMagic::JS_IS_CONSTRUCTING.
*
* This function calls CreateThis to generate a new |this| object, then
* overwrites the magic ThisV on the stack.
* call. This is called after we have pushed the formal arguments, but before
* pushing the callee token. When this is called, argcReg must contain the
* number of actual arguments (including bound or spread arguments; not
* including `undef` pushed in cases of argument underflow). calleeReg should
* contain the actual callee.
*/
void BaselineCacheIRCompiler::createThis(Register argcReg, Register calleeReg,
Register scratch, CallFlags flags,
bool isBoundFunction) {
Register scratch, Register scratch2,
CallFlags flags,
Maybe<uint32_t> numBoundArgs) {
MOZ_ASSERT(flags.isConstructing());
bool isBoundFunction = numBoundArgs.isSome();
// Derived constructors don't allocate a `this` object. They instead call
// `super`, and the base class constructor will allocate `this`.
if (flags.needsUninitializedThis()) {
storeThis(MagicValue(JS_UNINITIALIZED_LEXICAL), argcReg, flags);
masm.Push(MagicValue(JS_UNINITIALIZED_LEXICAL));
return;
}
// Save a reference to the start of the arguments, so that we can root
// them in CreateThisFromIC.
Register argvReg = scratch2;
masm.moveStackPtrTo(argvReg);
// Save live registers that don't have to be traced.
LiveGeneralRegisterSet liveNonGCRegs;
liveNonGCRegs.add(argcReg);
@ -3648,25 +3651,27 @@ void BaselineCacheIRCompiler::createThis(Register argcReg, Register calleeReg,
// CreateThis takes two arguments: callee, and newTarget.
// Push argv/argc for rooting in CreateThisFromIC
masm.push(argcReg);
masm.push(argvReg);
if (isBoundFunction) {
// Push the bound function's target as callee and newTarget.
Address boundTarget(calleeReg, BoundFunctionObject::offsetOfTargetSlot());
masm.unboxObject(boundTarget, scratch);
masm.push(scratch);
masm.push(scratch);
masm.push(calleeReg);
masm.push(calleeReg);
} else {
// Push newTarget:
loadStackObject(ArgumentKind::NewTarget, flags, argcReg, scratch);
masm.push(scratch);
// Push callee:
loadStackObject(ArgumentKind::Callee, flags, argcReg, scratch);
masm.push(scratch);
// Push callee.
masm.push(calleeReg);
}
// Call CreateThisFromIC.
using Fn =
bool (*)(JSContext*, HandleObject, HandleObject, MutableHandleValue);
bool (*)(JSContext*, HandleObject, HandleObject, Value*, uint32_t,
MutableHandleValue);
callVM<Fn, CreateThisFromIC>(masm);
#ifdef DEBUG
@ -3686,14 +3691,29 @@ void BaselineCacheIRCompiler::createThis(Register argcReg, Register calleeReg,
Address stubAddr(FramePointer, BaselineStubFrameLayout::ICStubOffsetFromFP);
masm.loadPtr(stubAddr, ICStubReg);
// Save |this| value back into pushed arguments on stack.
// Push |this|.
MOZ_ASSERT(!liveNonGCRegs.aliases(JSReturnOperand));
storeThis(JSReturnOperand, argcReg, flags);
masm.Push(TypedOrValueRegister(JSReturnOperand));
// Restore calleeReg. CreateThisFromIC may trigger a GC, so we reload the
// callee from the stub frame (which is traced) instead of spilling it to
// callee from the caller's frame (which is traced) instead of spilling it to
// the stack.
loadStackObject(ArgumentKind::Callee, flags, argcReg, calleeReg);
if (isBoundFunction) {
// Load the callee (which is a bound function).
// At this point, argcReg is the number of actual arguments being passed.
// For bound functions, this includes bound arguments. However, to compute
// the address of `callee` in the caller's frame, we need to know how many
// arguments were passed by the caller. This is argcReg - numBoundArgs.
// We pass in `numBoundArgs` so that loadStackObject can adjust accordingly.
loadStackObject(ArgumentKind::Callee, flags, argcReg, calleeReg,
*numBoundArgs);
// Load the target JSFunction.
Address boundTarget(calleeReg, BoundFunctionObject::offsetOfTargetSlot());
masm.unboxObject(boundTarget, calleeReg);
} else {
loadStackObject(ArgumentKind::Callee, flags, argcReg, calleeReg);
}
}
void BaselineCacheIRCompiler::updateReturnValue() {
@ -3753,11 +3773,6 @@ bool BaselineCacheIRCompiler::emitCallScriptedFunction(ObjOperandId calleeId,
masm.switchToObjectRealm(calleeReg, scratch);
}
if (isConstructing) {
createThis(argcReg, calleeReg, scratch, flags,
/* isBoundFunction = */ false);
}
pushArguments(argcReg, calleeReg, scratch, scratch2, flags, argcFixed,
/*isJitCall =*/true);
@ -3767,7 +3782,6 @@ bool BaselineCacheIRCompiler::emitCallScriptedFunction(ObjOperandId calleeId,
// Note that we use Push, not push, so that callJit will align the stack
// properly on ARM.
masm.PushCalleeToken(calleeReg, isConstructing);
masm.PushFrameDescriptorForJitCall(FrameType::BaselineStub, argcReg, scratch);
// Handle arguments underflow.
@ -3843,11 +3857,11 @@ bool BaselineCacheIRCompiler::emitCallInlinedFunction(ObjOperandId calleeId,
masm.switchToObjectRealm(calleeReg, scratch);
}
pushArguments(argcReg, calleeReg, scratch, scratch2, flags, argcFixed,
/*isJitCall =*/true);
Label baselineScriptDiscarded;
if (isConstructing) {
createThis(argcReg, calleeReg, scratch, flags,
/* isBoundFunction = */ false);
// CreateThisFromIC may trigger a GC and discard the BaselineScript.
// We have already called discardStack, so we can't use a FailurePath.
// Instead, we skip storing the ICScript in the JSContext and use a
@ -3868,12 +3882,8 @@ bool BaselineCacheIRCompiler::emitCallInlinedFunction(ObjOperandId calleeId,
masm.bind(&skip);
}
pushArguments(argcReg, calleeReg, scratch, scratch2, flags, argcFixed,
/*isJitCall =*/true);
// Note that we use Push, not push, so that callJit will align the stack
// properly on ARM.
masm.PushCalleeToken(calleeReg, isConstructing);
masm.PushFrameDescriptorForJitCall(FrameType::BaselineStub, argcReg, scratch);
// Handle arguments underflow.
@ -4035,34 +4045,26 @@ bool BaselineCacheIRCompiler::emitCallBoundScriptedFunction(
AutoStubFrame stubFrame(*this);
stubFrame.enter(masm, scratch);
Address boundTarget(calleeReg, BoundFunctionObject::offsetOfTargetSlot());
// If we're constructing, switch to the target's realm and create |this|. If
// we're not constructing, we switch to the target's realm after pushing the
// arguments and loading the target.
if (isConstructing) {
if (!isSameRealm) {
masm.unboxObject(boundTarget, scratch);
masm.switchToObjectRealm(scratch, scratch);
}
createThis(argcReg, calleeReg, scratch, flags,
/* isBoundFunction = */ true);
}
// Push all arguments, including |this|.
pushBoundFunctionArguments(argcReg, calleeReg, scratch, scratch2, flags,
numBoundArgs, /* isJitCall = */ true);
// Load the target JSFunction.
Address boundTarget(calleeReg, BoundFunctionObject::offsetOfTargetSlot());
masm.unboxObject(boundTarget, calleeReg);
if (!isConstructing && !isSameRealm) {
if (!isSameRealm) {
masm.switchToObjectRealm(calleeReg, scratch);
}
// Update argc.
masm.add32(Imm32(numBoundArgs), argcReg);
if (isConstructing) {
createThis(argcReg, calleeReg, scratch, scratch2, flags,
mozilla::Some(numBoundArgs));
}
// Load the start of the target JitCode.
Register code = scratch2;
masm.loadJitCodeRaw(calleeReg, code);

View file

@ -73,7 +73,7 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler {
bool updateArgc(CallFlags flags, Register argcReg, Register scratch);
void loadStackObject(ArgumentKind kind, CallFlags flags, Register argcReg,
Register dest);
Register dest, uint32_t extraArgs = 0);
void pushArguments(Register argcReg, Register calleeReg, Register scratch,
Register scratch2, CallFlags flags, uint32_t argcFixed,
bool isJitCall);
@ -93,9 +93,8 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler {
CallFlags flags, uint32_t numBoundArgs,
bool isJitCall);
void createThis(Register argcReg, Register calleeReg, Register scratch,
CallFlags flags, bool isBoundFunction);
template <typename T>
void storeThis(const T& newThis, Register argcReg, CallFlags flags);
Register scratch2, CallFlags flags,
mozilla::Maybe<uint32_t> numBoundArgs = mozilla::Nothing());
void updateReturnValue();
enum class NativeCallType { Native, ClassHook };

View file

@ -299,7 +299,9 @@ class ICCacheIRStub final : public ICStub {
void trace(JSTracer* trc);
bool traceWeak(JSTracer* trc);
ICCacheIRStub* clone(JSRuntime* rt, ICStubSpace& newSpace);
enum class ICScriptHandling { MarkActive, AssertActive };
ICCacheIRStub* clone(JSRuntime* rt, ICStubSpace& newSpace,
ICScriptHandling icScriptHandling);
// Returns true if this stub can call JS or VM code that can trigger a GC.
bool makesGCCalls() const;

View file

@ -243,6 +243,9 @@ uint32_t CacheIRCloner::getRawInt32Field(uint32_t stubOffset) {
const void* CacheIRCloner::getRawPointerField(uint32_t stubOffset) {
return reinterpret_cast<const void*>(readStubWord(stubOffset));
}
const ICScript* CacheIRCloner::getICScriptField(uint32_t stubOffset) {
return reinterpret_cast<const ICScript*>(readStubWord(stubOffset));
}
uint64_t CacheIRCloner::getRawInt64Field(uint32_t stubOffset) {
return static_cast<uint64_t>(readStubInt64(stubOffset));
}

View file

@ -239,6 +239,7 @@ class StubField {
// These fields take up a single word.
RawInt32,
RawPointer,
ICScript,
Shape,
WeakShape,
WeakGetterSetter,
@ -312,6 +313,8 @@ inline const char* StubFieldTypeName(StubField::Type ty) {
return "RawInt32";
case StubField::Type::RawPointer:
return "RawPointer";
case StubField::Type::ICScript:
return "ICScript";
case StubField::Type::Shape:
return "Shape";
case StubField::Type::WeakShape:

View file

@ -71,6 +71,7 @@ class MOZ_RAII CacheIRCloner {
JitCode* getJitCodeField(uint32_t stubOffset);
uint32_t getRawInt32Field(uint32_t stubOffset);
const void* getRawPointerField(uint32_t stubOffset);
const ICScript* getICScriptField(uint32_t stubOffset);
jsid getIdField(uint32_t stubOffset);
const Value getValueField(uint32_t stubOffset);
uint64_t getRawInt64Field(uint32_t stubOffset);

View file

@ -1119,6 +1119,7 @@ static void InitWordStubField(StubField::Type type, void* dest,
switch (type) {
case StubField::Type::RawInt32:
case StubField::Type::RawPointer:
case StubField::Type::ICScript:
case StubField::Type::AllocSite:
*static_cast<uintptr_t*>(dest) = value;
break;
@ -1179,6 +1180,7 @@ static void InitInt64StubField(StubField::Type type, void* dest,
break;
case StubField::Type::RawInt32:
case StubField::Type::RawPointer:
case StubField::Type::ICScript:
case StubField::Type::AllocSite:
case StubField::Type::Shape:
case StubField::Type::WeakShape:
@ -1209,7 +1211,8 @@ void CacheIRWriter::copyStubData(uint8_t* dest) const {
}
}
ICCacheIRStub* ICCacheIRStub::clone(JSRuntime* rt, ICStubSpace& newSpace) {
ICCacheIRStub* ICCacheIRStub::clone(JSRuntime* rt, ICStubSpace& newSpace,
ICScriptHandling icScriptHandling) {
const CacheIRStubInfo* info = stubInfo();
MOZ_ASSERT(info->makesGCCalls());
@ -1242,6 +1245,15 @@ ICCacheIRStub* ICCacheIRStub::clone(JSRuntime* rt, ICStubSpace& newSpace) {
InitWordStubField(type, dest, *srcField);
src += sizeof(uintptr_t);
dest += sizeof(uintptr_t);
if (type == StubField::Type::ICScript) {
auto* icScript = reinterpret_cast<ICScript*>(*srcField);
if (icScriptHandling == ICScriptHandling::MarkActive) {
icScript->setActive();
} else {
MOZ_ASSERT(icScriptHandling == ICScriptHandling::AssertActive);
MOZ_RELEASE_ASSERT(icScript->active());
}
}
} else {
const uint64_t* srcField = reinterpret_cast<const uint64_t*>(src);
InitInt64StubField(type, dest, *srcField);
@ -1278,6 +1290,7 @@ void jit::TraceCacheIRStub(JSTracer* trc, T* stub,
switch (fieldType) {
case Type::RawInt32:
case Type::RawPointer:
case Type::ICScript:
case Type::RawInt64:
case Type::Double:
break;
@ -1425,6 +1438,7 @@ bool jit::TraceWeakCacheIRStub(JSTracer* trc, T* stub,
return !isDead;
case Type::RawInt32:
case Type::RawPointer:
case Type::ICScript:
case Type::Shape:
case Type::JSObject:
case Type::Symbol:

View file

@ -1931,7 +1931,7 @@
receiver: ObjId
setter: ObjectField
rhs: ValId
icScript: RawPointerField
icScript: ICScriptField
sameRealm: BoolImm
nargsAndFlags: RawInt32Field
@ -2124,7 +2124,7 @@
args:
callee: ObjId
argc: Int32Id
icScript: RawPointerField
icScript: ICScriptField
flags: CallFlagsImm
argcFixed: UInt32Imm
@ -2558,7 +2558,7 @@
args:
receiver: ValId
getter: ObjectField
icScript: RawPointerField
icScript: ICScriptField
sameRealm: BoolImm
nargsAndFlags: RawInt32Field

View file

@ -238,6 +238,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
void writeRawPointerField(const void* ptr) {
addStubField(uintptr_t(ptr), StubField::Type::RawPointer);
}
void writeICScriptField(const ICScript* icScript) {
addStubField(uintptr_t(icScript), StubField::Type::ICScript);
}
void writeIdField(jsid id) {
addStubField(id.asRawBits(), StubField::Type::Id);
}

Some files were not shown because too many files have changed in this diff Show more