Moderate firefox Logic Error 🔧 Commit mapped

Overview

Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionIncorrect boundary conditions in the SVG component
ComponentLayout
Bug ClassLogic Error
Tracker2072438
Fix commitbbfcbae6ae57 (firefox) +55/-30
CISA KEVNot listed
CreditedMozilla
Disclosed2026-10-13

Changed Functions

FunctionChangeNotes
if
layout/base/nsBidiPresUtils.cpp
modified
if
layout/base/nsPresContext.cpp
modified

Files Changed

  • layout/base/nsBidiPresUtils.cpp
  • layout/base/nsPresContext.cpp
  • layout/base/nsPresContext.h
diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp
index 4f43772a96f..46ef10afdef 100644
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -12,6 +12,7 @@
 #include "mozilla/IntegerRange.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/Utf16.h"
 #include "mozilla/dom/Text.h"
 #include "mozilla/intl/Bidi.h"
@@ -342,8 +343,8 @@ struct MOZ_STACK_CLASS BidiParagraphData {
     }
   }
 
-  nsresult SetPara() {
-    if (mPresContext->BidiEngine().SetParagraph(mBuffer, mParaLevel).isErr()) {
+  nsresult SetPara(BidiEngine& aBidiEngine) {
+    if (aBidiEngine.SetParagraph(mBuffer, mParaLevel).isErr()) {
       return NS_ERROR_FAILURE;
     };
     return NS_OK;
@@ -356,21 +357,22 @@ struct MOZ_STACK_CLASS BidiParagraphData {
    * which is always either BidiDirection::LTR or
    * BidiDirection::RTL
    */
-  BidiEmbeddingLevel GetParagraphEmbeddingLevel() {
+  BidiEmbeddingLevel GetParagraphEmbeddingLevel(BidiEngine& aBidiEngine) {
     BidiEmbeddingLevel paraLevel = mParaLevel;
     if (paraLevel == BidiEmbeddingLevel::DefaultLTR() ||
         paraLevel == BidiEmbeddingLevel::DefaultRTL()) {
-      paraLevel = mPresContext->BidiEngine().GetParagraphEmbeddingLevel();
+      paraLevel = aBidiEngine.GetParagraphEmbeddingLevel();
     }
     return paraLevel;
   }
 
-  BidiEngine::ParagraphDirection GetParagraphDirection() {
-    return mPresContext->BidiEngine().GetParagraphDirection();
+  BidiEngine::ParagraphDirection GetParagraphDirection(
+      BidiEngine& aBidiEngine) {
+    return aBidiEngine.GetParagraphDirection();
   }
 
-  nsresult CountRuns(int32_t* runCount) {
-    auto result = mPresContext->BidiEngine().CountRuns();
+  nsresult CountRuns(int32_t* runCount, BidiEngine& aBidiEngine) {
+    auto result = aBidiEngine.CountRuns();
     if (result.isErr()) {
       return NS_ERROR_FAILURE;
     }
@@ -379,11 +381,10 @@ struct MOZ_STACK_CLASS BidiParagraphData {
   }
 
   void GetLogicalRun(int32_t aLogicalStart, int32_t* aLogicalLimit,
-                     BidiEmbeddingLevel* aLevel) {
-    mPresContext->BidiEngine().GetLogicalRun(aLogicalStart, aLogicalLimit,
-                                             aLevel);
+                     BidiEmbeddingLevel* aLevel, BidiEngine& aBidiEngine) {
+    aBidiEngine.GetLogicalRun(aLogicalStart, aLogicalLimit, aLevel);
     if (mIsVisual) {
-      *aLevel = GetParagraphEmbeddingLevel();
+      *aLevel = GetParagraphEmbeddingLevel(aBidiEngine);
     }
   }
 
@@ -883,12 +884,19 @@ nsresult nsBidiPresUtils::ResolveParagraph(BidiParagraphData* aBpd) {
 
   int32_t runCount;
 
-  nsresult rv = aBpd->SetPara();
+  UniquePtr<BidiEngine> bidiEngine = aBpd->mPresContext->GetBidiEngine();
+  ScopeExit e([aBpd, &bidiEngine]() {
+    aBpd->mPresContext->ReleaseBidiEngine(std::move(bidiEngine));
+  });
+
+  BidiEngine& bidi = *bidiEngine;
+
+  nsresult rv = aBpd->SetPara(bidi);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  BidiEmbeddingLevel embeddingLevel = aBpd->GetParagraphEmbeddingLevel();
+  BidiEmbeddingLevel embeddingLevel = aBpd->GetParagraphEmbeddingLevel(bidi);
 
-  rv = aBpd->CountRuns(&runCount);
+  rv = aBpd->CountRuns(&runCount, bidi);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t runLength = 0;     // the length of the current run of text
@@ -919,8 +927,9 @@ nsresult nsBidiPresUtils::ResolveParagraph(BidiParagraphData* aBpd) {
 #endif
 
   if (runCount == 1 && frameCount == 1 &&
-      aBpd->GetParagraphDirection() == BidiEngine::ParagraphDirection::LTR &&
-      aBpd->GetParagraphEmbeddingLevel() == 0) {
+      aBpd->GetParagraphDirection(bidi) ==
+          BidiEngine::ParagraphDirection::LTR &&
+      aBpd->GetParagraphEmbeddingLevel(bidi) == 0) {
     // We have a single left-to-right frame in a left-to-right paragraph,
     // without bidi isolation from the surrounding text.
     // Make sure that the embedding level and base level frame properties aren't
@@ -948,7 +957,7 @@ nsresult nsBidiPresUtils::ResolveParagraph(BidiParagraphData* aBpd) {
   auto storeBidiDataToFrame = [&]() {
     FrameBidiData bidiData;
     bidiData.embeddingLevel = embeddingLevel;
-    bidiData.baseLevel = aBpd->GetParagraphEmbeddingLevel();
+    bidiData.baseLevel = aBpd->GetParagraphEmbeddingLevel(bidi);
     // If a control character doesn't have a lower embedding level than
     // both the preceding and the following frame, it isn't something
     // needed for getting the correct result. This optimization should
@@ -1012,7 +1021,7 @@ nsresult nsBidiPresUtils::ResolveParagraph(BidiParagraphData* aBpd) {
         break;
       }
       int32_t lineOffset = logicalLimit;
-      aBpd->GetLogicalRun(lineOffset, &logicalLimit, &embeddingLevel);
+      aBpd->GetLogicalRun(lineOffset, &logicalLimit, &embeddingLevel, bidi);
       runLength = logicalLimit - lineOffset;
     }  // if (runLength <= 0)
 
@@ -2502,18 +2511,24 @@ nsresult nsBidiPresUtils::ProcessTextForRenderingContext(
   nsDependentSubstring text(aText, aLength);
   auto separatorIndex = text.FindCharInSet(kSeparators);
   if (separatorIndex == kNotFound) {
-    return ProcessText(text.BeginReading(), text.Length(), aBaseLevel,
-                       aPresContext, processor, aMode, aPosResolve,
-                       aPosResolveCount, aWidth, aPresContext->BidiEngine());
+    UniquePtr bidiEngine = aPresContext->GetBidiEngine();
+    auto rv = ProcessText(text.BeginReading(), text.Length(), aBaseLevel,
+                          aPresContext, processor, aMode, aPosResolve,
+                          aPosResolveCount, aWidth, *bidiEngine);
+    aPresContext->ReleaseBidiEngine(std::move(bidiEngine));
+    return rv;
   }
 
   // We need to replace any block or segment separators with space for bidi
   // processing, so make a local copy.
   nsAutoString localText(text);
   ReplaceSeparators(localText, separatorIndex);
-  return ProcessText(localText.BeginReading(), localText.Length(), aBaseLevel,
-                     aPresContext, processor, aMode, aPosResolve,
-                     aPosResolveCount, aWidth, aPresContext->BidiEngine());
+  UniquePtr bidiEngine = aPresContext->GetBidiEngine();
+  auto rv = ProcessText(localText.BeginReading(), localText.Length(),
+                        aBaseLevel, aPresContext, processor, aMode, aPosResolve,
+                        aPosResolveCount, aWidth, *bidiEngine);
+  aPresContext->ReleaseBidiEngine(std::move(bidiEngine));
+  return rv;
 }
 
 /* static */
diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp
index 06fe27c8d6c..2419d4eaced 100644
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -2829,13 +2829,13 @@ uint64_t nsPresContext::GetUndisplayedRestyleGeneration() const {
   return mRestyleManager->GetUndisplayedRestyleGeneration();
 }
 
-mozilla::intl::Bidi& nsPresContext::BidiEngine() {
+UniquePtr<intl::Bidi> nsPresContext::GetBidiEngine() {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!mBidiEngine) {
-    mBidiEngine = MakeUnique<mozilla::intl::Bidi>();
+  if (mBidiEngine) {
+    return std::move(mBidiEngine);
   }
-  return *mBidiEngine;
+  return MakeUnique<mozilla::intl::Bidi>();
 }
 
 void nsPresContext::FlushFontFeatureValues() {
diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h
index dd13711ab28..a965fbedc65 100644
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -1087,7 +1087,17 @@ class nsPresContext : public nsISupports,
 
   void UpdateContainerQueryStylesAndAnchorPosLayout();
 
-  mozilla::intl::Bidi& BidiEngine();
+  // Call GetBidiEngine to get a bidi-resolution engine from the prescontext.
+  // This may be an previously-cached object or a newly-constructed one.
+  // The caller then has sole ownership of the returned object.
+  mozilla::UniquePtr<mozilla::intl::Bidi> GetBidiEngine();
+
+  // Call ReleaseBidiEngine when finished with a bidi-resolution engine. This
+  // allows the prescontext to keep it around for subsequent re-use.
+  void ReleaseBidiEngine(
+      mozilla::UniquePtr<mozilla::intl::Bidi>&& aBidiEngine) {
+    mBidiEngine = std::move(aBidiEngine);
+  }
 
   gfxFontFeatureValueSet* GetFontFeatureValuesLookup() const {
     return mFontFeatureValuesLookup;
Loading diff…