Firefox · DOM
CVE-2026-118016
Logic Error in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdom/base/Document.cpp |
modified | |
fordom/base/Document.cpp |
modified | |
ifdom/base/FragmentOrElement.cpp |
modified | |
ifdom/base/FragmentOrElement.h |
modified | |
fordom/base/RadioGroupContainer.cpp |
modified | |
nsIContentdom/base/RadioGroupContainer.h |
modified | |
RadioGroupContainerdom/base/RadioGroupContainer.h |
modified | |
mRadioGroupContainerdom/html/HTMLInputElement.cpp |
modified | |
mIsUserInteractingdom/html/HTMLInputElement.cpp |
modified |
Files Changed
dom/base/Document.cppdom/base/Document.hdom/base/FragmentOrElement.cppdom/base/FragmentOrElement.hdom/base/RadioGroupContainer.cppdom/base/RadioGroupContainer.hdom/html/HTMLInputElement.cppdom/html/HTMLInputElement.h
Patch
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index e9e2dadc775..3a3c149ffae 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -2744,9 +2744,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(Document)
cb.NoteXPCOMChild(registry);
}
- if (tmp->mRadioGroupContainer) {
- RadioGroupContainer::Traverse(tmp->mRadioGroupContainer.get(), cb);
- }
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRadioGroupContainer)
for (auto& sheets : tmp->mAdditionalSheets) {
tmp->TraverseStyleSheets(sheets, "mAdditionalSheets[<origin>][i]", cb);
@@ -2958,7 +2956,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document)
DocumentOrShadowRoot::Unlink(tmp);
CustomElementRegistry::RemoveScopedRegistry(*tmp);
- tmp->mRadioGroupContainer = nullptr;
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mRadioGroupContainer)
// Document has a pretty complex destructor, so we're going to
// assume that *most* cycles you actually want to break somewhere
@@ -21449,7 +21447,7 @@ FragmentDirective* Document::FragmentDirective() {
RadioGroupContainer& Document::OwnedRadioGroupContainer() {
if (!mRadioGroupContainer) {
- mRadioGroupContainer = MakeUnique<RadioGroupContainer>();
+ mRadioGroupContainer = MakeRefPtr<RadioGroupContainer>();
}
return *mRadioGroupContainer;
}
diff --git a/dom/base/Document.h b/dom/base/Document.h
index 8d9a21728b5..48350023b80 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -6021,7 +6021,7 @@ class Document : public nsINode,
RefPtr<ResizeObserver> mAutoSizeImageObserver;
RefPtr<class FragmentDirective> mFragmentDirective;
- UniquePtr<RadioGroupContainer> mRadioGroupContainer;
+ RefPtr<RadioGroupContainer> mRadioGroupContainer;
nsCOMPtr<nsIURI> mTLSCertificateBindingURI;
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index 1d462b12469..35f2ff46671 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -390,9 +390,8 @@ void FragmentOrElement::nsExtendedDOMSlots::TraverseExtendedSlots(
if (mAnimations) {
mAnimations->Traverse(aCb);
}
- if (mRadioGroupContainer) {
- RadioGroupContainer::Traverse(mRadioGroupContainer.get(), aCb);
- }
+ ImplCycleCollectionTraverse(aCb, mRadioGroupContainer,
+ "mExtendedSlots->mRadioGroupContainer");
}
size_t FragmentOrElement::nsExtendedDOMSlots::SizeOfExcludingThis(
diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h
index 6564d35edab..3ceaf4a237f 100644
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -96,7 +96,7 @@ class FragmentOrElement : public nsIContent {
RadioGroupContainer& OwnedRadioGroupContainer() {
auto* slots = ExtendedDOMSlots();
if (!slots->mRadioGroupContainer) {
- slots->mRadioGroupContainer = MakeUnique<RadioGroupContainer>();
+ slots->mRadioGroupContainer = MakeRefPtr<RadioGroupContainer>();
}
return *slots->mRadioGroupContainer;
}
@@ -203,7 +203,7 @@ class FragmentOrElement : public nsIContent {
* RadioGroupContainer for radio buttons grouped under this disconnected
* element.
*/
- UniquePtr<RadioGroupContainer> mRadioGroupContainer;
+ RefPtr<RadioGroupContainer> mRadioGroupContainer;
/**
* Scroll state of this element's scroll container frame, saved while the
diff --git a/dom/base/RadioGroupContainer.cpp b/dom/base/RadioGroupContainer.cpp
index cfb8d23026f..c208c6aa5ca 100644
--- a/dom/base/RadioGroupContainer.cpp
+++ b/dom/base/RadioGroupContainer.cpp
@@ -29,22 +29,11 @@ struct nsRadioGroupStruct {
RadioGroupContainer::RadioGroupContainer() = default;
-RadioGroupContainer::~RadioGroupContainer() {
- for (const auto& group : mRadioGroups) {
- for (const auto& button : group.GetData()->mRadioButtons.AsSpan()) {
- // When the radio group container is being cycle-collected, any remaining
- // connected buttons will also be in the process of being cycle-collected.
- // Here, we unset the button's reference to the container so that when it
- // is collected it does not attempt to remove itself from a potentially
- // already deleted radio group.
- button->DisconnectRadioGroupContainer();
- }
- }
-}
+RadioGroupContainer::~RadioGroupContainer() = default;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(RadioGroupContainer)
-/* static */
-void RadioGroupContainer::Traverse(RadioGroupContainer* tmp,
- nsCycleCollectionTraversalCallback& cb) {
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(RadioGroupContainer)
for (const auto& entry : tmp->mRadioGroups) {
nsRadioGroupStruct* radioGroup = entry.GetWeak();
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
@@ -57,7 +46,20 @@ void RadioGroupContainer::Traverse(RadioGroupContainer* tmp,
cb.NoteXPCOMChild(ToSupports(button));
}
}
-}
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(RadioGroupContainer)
+ for (const auto& group : tmp->mRadioGroups) {
+ for (const auto& button : group.GetData()->mRadioButtons.AsSpan()) {
+ // Any remaining connected buttons are also being cycle-collected. Unset
+ // the button's reference to the container so that when it is collected
+ // it does not attempt to remove itself from an already cleared radio
+ // group.
+ button->DisconnectRadioGroupContainer();
+ }
+ }
+ tmp->mRadioGroups.Clear();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
size_t RadioGroupContainer::SizeOfIncludingThis(
MallocSizeOf aMallocSizeOf) const {
diff --git a/dom/base/RadioGroupContainer.h b/dom/base/RadioGroupContainer.h
index 24291fa2e83..4be15f8f97d 100644
--- a/dom/base/RadioGroupContainer.h
+++ b/dom/base/RadioGroupContainer.h
@@ -6,6 +6,8 @@
#define mozilla_dom_nsRadioGroupStruct_h
#include "nsClassHashtable.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsISupportsImpl.h"
class nsIContent;
@@ -16,11 +18,11 @@ struct nsRadioGroupStruct;
class RadioGroupContainer final {
public:
+ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(RadioGroupContainer)
+ NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(RadioGroupContainer)
+
RadioGroupContainer();
- ~RadioGroupContainer();
- static void Traverse(RadioGroupContainer* tmp,
- nsCycleCollectionTraversalCallback& cb);
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
template <typename VisitCallback>
@@ -53,6 +55,8 @@ class RadioGroupContainer final {
nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
private:
+ ~RadioGroupContainer();
+
Span<const RefPtr<HTMLInputElement>> GetButtonsInGroup(
nsRadioGroupStruct* aGroup) const;
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index 2c34f622855..4ee43d29d8c 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1160,8 +1160,7 @@ HTMLInputElement::HTMLInputElement(already_AddRefed<dom::NodeInfo> aNodeInfo,
mHasBeenTypePassword(false),
mHasPatternAttribute(false),
mUserChangedSinceFocus(false),
- mIsUserInteracting(false),
- mRadioGroupContainer(nullptr) {
+ mIsUserInteracting(false) {
// If size is above 512, mozjemalloc allocates 1kB, see
// memory/build/mozjemalloc.cpp
static_assert(sizeof(HTMLInputElement) <= 512,
@@ -1250,6 +1249,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement,
TextControlElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRadioGroupContainer)
if (tmp->IsSingleLineTextControl(false) && tmp->mInputData.mState) {
tmp->mInputData.mState->Traverse(cb);
}
@@ -1263,6 +1263,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
TextControlElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mRadioGroupContainer)
if (tmp->IsSingleLineTextControl(false) && tmp->mInputData.mState) {
tmp->mInputData.mState->Unlink();
}
diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h
index a25389d24c6..3827cffbd6a 100644
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1695,7 +1695,7 @@ class HTMLInputElement final : public TextControlElement,
* The radio group container containing the group the element is a part of.
* This allows the element to only access a container it has been added to.
*/
- RadioGroupContainer* mRadioGroupContainer;
+ RefPtr<RadioGroupContainer> mRadioGroupContainer;
struct nsFilePickerFilter {
nsFilePickerFilter() : mFilterMask(0) {}
Loading diff…
References
On This Page