Firefox · Layout
CVE-2026-109762
Logic Error in Layout
Overview
Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
iflayout/base/nsBidiPresUtils.cpp |
modified | |
iflayout/base/nsPresContext.cpp |
modified |
Files Changed
layout/base/nsBidiPresUtils.cpplayout/base/nsPresContext.cpplayout/base/nsPresContext.h
Patch
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…
References
On This Page