Firefox · SpiderMonkey
CVE-2026-100825
Logic Error in SpiderMonkey
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifjs/src/vm/Shape.cpp |
modified | |
forjs/src/jit-test/tests/fuses/objectfuse-property-remove-oom.js |
modified | |
ifjs/src/jit-test/tests/fuses/objectfuse-property-remove-oom.js |
modified |
Files Changed
js/src/jit-test/tests/fuses/objectfuse-property-remove-oom.jsjs/src/vm/ObjectFuse.cppjs/src/vm/ObjectFuse.hjs/src/vm/Shape.cppjs/src/vm/Watchtower.cppjs/src/vm/Watchtower.h
Patch
diff --git a/js/src/vm/ObjectFuse.cpp b/js/src/vm/ObjectFuse.cpp
index ae42c0e5159..3bcbc7d321d 100644
--- a/js/src/vm/ObjectFuse.cpp
+++ b/js/src/vm/ObjectFuse.cpp
@@ -147,8 +147,15 @@ void ObjectFuse::handlePropertyRemove(JSContext* cx, PropertyInfo prop,
bumpGeneration();
invalidateDependentIonScriptsForProperty(cx, prop, "removed property");
- // Ensure a new property with this slot number will have the correct initial
- // state.
+ // We want to mark the removed property's slot Untracked, but the property
+ // removal can still fail due to OOM, leaving existing SetSlot stubs valid.
+ // Mark the property NotConstant until we call finishPropertyRemove.
+ setPropertyState(prop, PropertyState::NotConstant);
+}
+
+void ObjectFuse::finishPropertyRemove(PropertyInfo prop) {
+ // See ObjectFuse::handlePropertyRemove comment above.
+ MOZ_ASSERT(getPropertyState(prop) == PropertyState::NotConstant);
setPropertyState(prop, PropertyState::Untracked);
}
diff --git a/js/src/vm/ObjectFuse.h b/js/src/vm/ObjectFuse.h
index 3db30c050ee..2ed0780df99 100644
--- a/js/src/vm/ObjectFuse.h
+++ b/js/src/vm/ObjectFuse.h
@@ -226,6 +226,7 @@ class ObjectFuse {
void handlePropertyValueChange(JSContext* cx, PropertyInfo prop);
void handlePropertyRemove(JSContext* cx, PropertyInfo prop,
bool* wasTrackedProp);
+ void finishPropertyRemove(PropertyInfo prop);
void handleTeleportingShadowedProperty(JSContext* cx, PropertyInfo prop);
void handleTeleportingProtoMutation(JSContext* cx);
void handleShadowedGlobalProperty(JSContext* cx, PropertyInfo prop);
diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp
index bcced8d7553..7652e6c85a3 100644
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -980,6 +980,10 @@ bool NativeObject::removeProperty(JSContext* cx, Handle<NativeObject*> obj,
obj->maybeFreeDictionaryPropSlots(cx, dictMap, mapLength);
}
+ if (wasTrackedObjectFuseProp) {
+ Watchtower::finishPropertyRemove(cx, obj, prop);
+ }
+
return true;
}
diff --git a/js/src/vm/Watchtower.cpp b/js/src/vm/Watchtower.cpp
index 2bf9062e36c..fb29715ab16 100644
--- a/js/src/vm/Watchtower.cpp
+++ b/js/src/vm/Watchtower.cpp
@@ -648,6 +648,15 @@ bool Watchtower::watchPropertyRemoveSlow(JSContext* cx,
return true;
}
+// static
+void Watchtower::finishPropertyRemove(JSContext* cx, NativeObject* obj,
+ PropertyInfo propInfo) {
+ MOZ_ASSERT(obj->hasObjectFuse());
+ if (auto* objFuse = cx->zone()->objectFuses.get(obj)) {
+ objFuse->finishPropertyRemove(propInfo);
+ }
+}
+
// static
bool Watchtower::watchPropertyFlagsChangeSlow(JSContext* cx,
Handle<NativeObject*> obj,
diff --git a/js/src/vm/Watchtower.h b/js/src/vm/Watchtower.h
index a5f5a68ab74..a54fe01c7c2 100644
--- a/js/src/vm/Watchtower.h
+++ b/js/src/vm/Watchtower.h
@@ -118,6 +118,8 @@ class Watchtower {
return watchPropertyRemoveSlow(cx, obj, id, propInfo,
wasTrackedObjectFuseProp);
}
+ static void finishPropertyRemove(JSContext* cx, NativeObject* obj,
+ PropertyInfo propInfo);
static bool watchPropertyFlagsChange(JSContext* cx, Handle<NativeObject*> obj,
HandleId id, PropertyInfo propInfo,
PropertyFlags newFlags) {
diff --git a/js/src/jit-test/tests/fuses/objectfuse-property-remove-oom.js b/js/src/jit-test/tests/fuses/objectfuse-property-remove-oom.js
new file mode 100644
index 00000000000..36499da5e39
--- /dev/null
+++ b/js/src/jit-test/tests/fuses/objectfuse-property-remove-oom.js
@@ -0,0 +1,12 @@
+function f() {
+ for (var i = 0; i < 50; i++) {
+ var v = {};
+ globalProp = v;
+ assertEq(globalProp, v);
+ if (i == 40) {
+ delete this.globalProp;
+ }
+ }
+}
+f();
+oomTest(f);
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/js/src/jit-test/tests/fuses/objectfuse-property-remove-oom.js b/js/src/jit-test/tests/fuses/objectfuse-property-remove-oom.js
new file mode 100644
index 00000000000..36499da5e39
--- /dev/null
+++ b/js/src/jit-test/tests/fuses/objectfuse-property-remove-oom.js
@@ -0,0 +1,12 @@
+function f() {
+ for (var i = 0; i < 50; i++) {
+ var v = {};
+ globalProp = v;
+ assertEq(globalProp, v);
+ if (i == 40) {
+ delete this.globalProp;
+ }
+ }
+}
+f();
+oomTest(f);
Loading diff…
References
On This Page