ReSet can only be called from main thread (the only thread that uses layout cache) or when lineNumber is same (same document line number is only handled by one thread). Adjust LineMayCache could make significant lines maps to unique cache position (change || to && seems work in Notepad4), but that requires some calculation and proof, and is hard to get right.
but not dangling here is no need to mannerly reset: @@ -599,10 +599,7 @@ } if (pos < cache.size()) { - if (cache[pos] && !cache[pos]->CanHold(lineNumber, maxChars)) { - cache[pos]->ReSet(lineNumber, maxChars); - } - if (!cache[pos]) { + if (!cache[pos] || !cache[pos]->CanHold(lineNumber, maxChars)) { cache[pos] = std::make_shared<LineLayout>(lineNumber, maxChars); } #ifdef CHECK_LLC
with following change for Notepad4: @@ -640,6 +640,10 @@ uint32_t EditView::LayoutLine(const EditModel &model, Surface *surface, const Vi const XYPOSITION xBeginSegment = xPosition; for (int i = 0; i < ts.length; i++) { + if (iByte > static_cast<unsigned>(ll->numCharsInLine)) { + printf("data race: lineNumber=%zd/%zd iByte=%u/%d\n", line, ll->LineNumber(), iByte, ll->numCharsInLine); + throw iByte; + } xPosition = ll->positions[iByte] + xBeginSegment; ll->positions[iByte++] = xPosition; } I can reproduce...
Following is test program to show multiple significant lines may mapped to same cache position: #define _CRT_SECURE_NO_WARNINGS #include <cstdint> #include <cstdlib> #include <cstdio> #include <algorithm> #include <memory> #include <vector> #include <map> struct LineLayout { int lineNumber; LineLayout(int lineNumber_) noexcept : lineNumber{lineNumber_} {} int LineNumber() const noexcept { return lineNumber; } bool CanHold(int lineDoc) const noexcept { return lineNumber == lineDoc; } }; constexpr...
data race in multi-threaded word wrap
It can be used for other places, e.g. all the lineRange.
Then using GetFinalPathNameByHandleW() or compare the file ids similar to std::filesystem::equivalent() could fix the problem. https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_info
That's not possible in sensible implementation, but new code is more simple and readable. I patched ScintillaWin::CaseMapString() to do custom text transliteration (which is the easiest way to handle multiple selections, much easy than iterate and manipulate selections in application). I found out of bounds read when doing C escape/unescape (e.g. \\ => \\\\).