From ef42bb46c5182037e276ceb251e604b1bcff8f38 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 15 Dec 2023 21:35:28 +1100 Subject: Bug [#2289]. Protect SCI_REPLACETARGET* from application changing target in notification handlers. --- doc/ScintillaHistory.html | 5 +++++ src/Editor.cxx | 28 +++++++++++++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index ca780bc46..00023b102 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -625,6 +625,11 @@ With a document that does not have the SC_DOCUMENTOPTION_TEXT_LARGE option set, allocating more than 2G (calling SCI_ALLOCATE or similar) will now fail with SC_STATUS_FAILURE. +
  • + Protect SCI_REPLACETARGET, SCI_REPLACETARGETMINIMAL, and SCI_REPLACETARGETRE from + application changing target in notification handlers. + Bug #2289. +
  • Release 5.4.0 diff --git a/src/Editor.cxx b/src/Editor.cxx index ceaa1398d..28d680d7a 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -5776,13 +5776,17 @@ Sci::Position Editor::GetTag(char *tagValue, int tagNumber) { Sci::Position Editor::ReplaceTarget(ReplaceType replaceType, std::string_view text) { UndoGroup ug(pdoc); + + std::string substituted; // Copy in case of re-entrance + if (replaceType == ReplaceType::patterns) { Sci::Position length = text.length(); const char *p = pdoc->SubstituteByPosition(text.data(), &length); if (!p) { return 0; } - text = std::string_view(p, length); + substituted.assign(p, length); + text = substituted; } if (replaceType == ReplaceType::minimal) { @@ -5797,19 +5801,25 @@ Sci::Position Editor::ReplaceTarget(ReplaceType replaceType, std::string_view te targetRange = SelectionSegment(start, SelectionPosition(range.end)); } + // Make a copy of targetRange in case callbacks use target + SelectionSegment replaceRange = targetRange; + // Remove the text inside the range - if (targetRange.Length() > 0) - pdoc->DeleteChars(targetRange.start.Position(), targetRange.Length()); - targetRange.end = targetRange.start; + if (replaceRange.Length() > 0) + pdoc->DeleteChars(replaceRange.start.Position(), replaceRange.Length()); // Realize virtual space of target start - const Sci::Position startAfterSpaceInsertion = RealizeVirtualSpace(targetRange.start.Position(), targetRange.start.VirtualSpace()); - targetRange.start.SetPosition(startAfterSpaceInsertion); - targetRange.end = targetRange.start; + const Sci::Position startAfterSpaceInsertion = RealizeVirtualSpace(replaceRange.start.Position(), replaceRange.start.VirtualSpace()); + replaceRange.start.SetPosition(startAfterSpaceInsertion); + replaceRange.end = replaceRange.start; // Insert the new text - const Sci::Position lengthInserted = pdoc->InsertString(targetRange.start.Position(), text); - targetRange.end.SetPosition(targetRange.start.Position() + lengthInserted); + const Sci::Position lengthInserted = pdoc->InsertString(replaceRange.start.Position(), text); + replaceRange.end.SetPosition(replaceRange.start.Position() + lengthInserted); + + // Copy back to targetRange in case application is chaining modifications + targetRange = replaceRange; + return text.length(); } -- cgit v1.2.3