aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2023-12-15 21:35:28 +1100
committerNeil <nyamatongwe@gmail.com>2023-12-15 21:35:28 +1100
commitef42bb46c5182037e276ceb251e604b1bcff8f38 (patch)
tree0def92c82c0923625a468a2e36405888874d3aa4
parent361218f4984d429c1a518cb1dbd94612eab0ecaa (diff)
downloadscintilla-mirror-ef42bb46c5182037e276ceb251e604b1bcff8f38.tar.gz
Bug [#2289]. Protect SCI_REPLACETARGET* from application changing target in
notification handlers.
-rw-r--r--doc/ScintillaHistory.html5
-rw-r--r--src/Editor.cxx28
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.
</li>
+ <li>
+ Protect SCI_REPLACETARGET, SCI_REPLACETARGETMINIMAL, and SCI_REPLACETARGETRE from
+ application changing target in notification handlers.
+ <a href="https://sourceforge.net/p/scintilla/bugs/2289/">Bug #2289</a>.
+ </li>
</ul>
<h3>
<a href="https://www.scintilla.org/scintilla540.zip">Release 5.4.0</a>
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();
}